-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow creating custom targets in a domain #9662
Comments
I think something like this would be a nice tool. Your nicely detailed report gave my an idea for how this perhaps could be implemented as a posttransform in a very generic way without having to touch the domains, except for adding the doEverythingAsNormalExceptRenderingButStillInsertAnchors-option.
In your example you could then do: MyClass
=======
MyClass does foo and has an attribute :py:attr:`bar`:
.. py:class:: MyClass
:doEverythingAsNormalExceptRenderingButStillInsertAnchors:
Nothing of of this text gets rendered due to the option.
.. py:class:: NestedClass
.. py::method:: doStuff()
.. py::attribute:: bar
Still nothing of this is rendered, as long as we are in MyClass.
.. 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`. In that case you declare everything as normal, and all references |
In python domain's case, you can use For example, this
In this short example, I used "doctree-read" event to implement quickly. But this is just an example. I think this helps you to implement idea 2. |
Oops. I have to answer to your questions.
It should be a public API. So it's a mistake not to be documented. I'll add it soon.
No. The goal of the directives that inherits |
@jakobandersen your idea looks similar to implementation idea 1 except that directly extracting the ids in @tk0miya Based on those function we could implement a rather universal directive similar to those in idea 3. |
Indeed, it is close to idea 1. You need to be very careful with |
It's difficult. Domains can support many kinds of data at same time. So it's difficult to register it through single method. For example, python domain supports "objects" and "modules". So it provides |
As proof of concept I have created #9671 with the post-transform idea. |
Now I understand your concerns better. Also thank you for your proof of concept with the post transform. Before reporting this issue I had another hack (subclassing all directives and removing all children instead of replacing the node). Yours is much smarter. I toyed with it a little but noticed a tiny flaw: the targets are placed as span before the target (that's not the bad part) but are also considered to belong logically to the "previous part" (targets logically belong to the "next part"). Here is an example:
The generated target is in the (HTML-element) section belonging to "Introduction" instead of being in the section of "myFunc is an awesome guy". I took your draft and ported it into the (Remark: changing the node type from Note to self: maybe rename option |
The method takes an string as type, so "module"/"mod" would be valid for that. The additional arguments to the directive can be passed as keyword arguments. .. domaintarget::
:domain: py
:subdomain: attr
:signature: bar
:signature: bar2 (event multiple signature might be allowed)
:otherarg: blub
:nextarg: being translated to the two calls # domain.note_object(subdomain/type: str, signature: str, node_id/target: str, *kwargs)
py_domain.note_object("attr", "bar", <node_id>, otherarg=blub, nextarg=True)
py_domain.note_object("attr", "bar2", <node_id>, otherarg=blub, nextarg=True) The domain knows that a module (or whatever it is) has keyword arguments and can process them accordingly (or throw an error if they mismatch or are missing). While this being more universal solution than adding a .. py:class:: MyClass
:hidden:
.. domaintarget::
:domain: py
:subdomain: class
:signature: MyClass This can be made more ergonomic if .. domaintarget:: py class
MyClass or even .. domaintarget:: py class MyClass |
Add doc for ObjectDescription (refs: #9662)
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.
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.
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
Implementation idea 1
ObjectDescription
already has aadd_target_and_index()
which is essentially all what we need.run()
, these might need additional adjustments:targetandindexonly:
(a bad name but will do for this report) and only generate a "target" node.Call
add_target_and_index()
with that target node.ObjectDescription
and some minor changes in those classes overridingrun()
.Open questions:
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
?Implementation idea 2
.. py:whatever::
directive to a.. py:whatever-target:
directive which takes a signature as argument and produces the corresponding target and index... _reference-label:
add_target_and_index()
, e.g. works with headers as target.Implementation idea 3
.. domaintarget::
directive with options which would produce for any domain and any signature a suitable 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 nodeAvoids 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
The text was updated successfully, but these errors were encountered: