3

Using the Sphinx "TODO" Directive example I would like to reference the todo instances embedded within a .rst file. For example, if the .rst file content contains:

.. todo:: foo

.. todo:: bar

I can see that the following code (taken from the Sphinx TODO example page)

class TodoDirective(SphinxDirective):

    # this enables content in the directive
    has_content = True

    def run(self):
        targetid = 'todo-%d' % self.env.new_serialno('todo')
        targetnode = nodes.target('', '', ids=[targetid])

        todo_node = todo('\n'.join(self.content))
        todo_node += nodes.title(_('Todo'), _('Todo'))
        self.state.nested_parse(self.content, self.content_offset, todo_node)

        if not hasattr(self.env, 'todo_all_todos'):
            self.env.todo_all_todos = []

        self.env.todo_all_todos.append({
            'docname': self.env.docname,
            'lineno': self.lineno,
            'todo': todo_node.deepcopy(),
            'target': targetnode,
        })

        return [targetnode, todo_node]

Creates target nodes with ids: todo-0 and todo-1. That are successfully referenced by embedding the directive in a .rst file as:

.. todolist::

What I would like to do is reference the todo items within a .rst file like this:

:ref:`todo-0`
:ref:`todo-1`

This would require getting the TodoDirective to generate a label for each target node. I have not been able to figure out how to do so.

This simple project is posted here: https://github.com/natersoz/sphinx_sandbox

mzjn
  • 48,958
  • 13
  • 128
  • 248
natersoz
  • 1,674
  • 2
  • 19
  • 29

2 Answers2

4

I had the same problem as you and was able to resolve the issue by looking at the autosectionlabel extension.

What they do there is to add the reference to the labels domain data. I got it working inside a custom directive like so:

nodeId = nodes.make_id("some-id")
self.env.app.env.domaindata["std"]["labels"][nodeId] = self.env.docname, nodeId, "Title"
section = nodes.section(ids=[nodeId])
section.append(nodes.title(text="Title"))

Key is the second line of the code above.

Also you want to add the label to the anonlabels to be able to reference it via

:ref:`foo <nodeId>`

like so:

self.env.app.env.domaindata["std"]["anonlabels"][nodeId] = self.env.docname, nodeId
Woltan
  • 13,723
  • 15
  • 78
  • 104
  • Thanks - I *almost* have this working. Have to task switch out and might take me some time to get back to it. Thank you so much! – natersoz Oct 07 '20 at 17:09
1

I found one way to perform this operation. It likely only works for HTML output:

`Text related to todo-0 <introduction.html#todo-0>`_

This reference link will successfully link to the TODO. All other reference attempts fail. i.e. These all fail:

Note: these syntaxes do not work::

    `introduction.html#todo-1`_

    :ref:`introduction.html#todo-1`

    :ref:`todo-1`
natersoz
  • 1,674
  • 2
  • 19
  • 29