2019-02-08 11:03:09 -06:00
|
|
|
from docutils import nodes
|
|
|
|
from docutils.parsers.rst import Directive
|
2019-02-18 07:38:42 -06:00
|
|
|
|
2019-02-08 11:03:09 -06:00
|
|
|
from sphinx.locale import _
|
2019-02-25 05:02:24 -06:00
|
|
|
from sphinx.util.docutils import SphinxDirective
|
2019-02-08 11:03:09 -06:00
|
|
|
|
|
|
|
|
|
|
|
class todo(nodes.Admonition, nodes.Element):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class todolist(nodes.General, nodes.Element):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def visit_todo_node(self, node):
|
|
|
|
self.visit_admonition(node)
|
|
|
|
|
|
|
|
|
|
|
|
def depart_todo_node(self, node):
|
|
|
|
self.depart_admonition(node)
|
|
|
|
|
|
|
|
|
|
|
|
class TodolistDirective(Directive):
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
return [todolist('')]
|
|
|
|
|
|
|
|
|
2019-02-18 07:38:42 -06:00
|
|
|
class TodoDirective(SphinxDirective):
|
2019-02-08 11:03:09 -06:00
|
|
|
|
|
|
|
# this enables content in the directive
|
|
|
|
has_content = True
|
|
|
|
|
|
|
|
def run(self):
|
2019-02-18 07:38:42 -06:00
|
|
|
targetid = 'todo-%d' % self.env.new_serialno('todo')
|
2019-02-08 11:03:09 -06:00
|
|
|
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)
|
|
|
|
|
2019-02-18 07:38:42 -06:00
|
|
|
if not hasattr(self.env, 'todo_all_todos'):
|
|
|
|
self.env.todo_all_todos = []
|
2019-02-08 11:03:09 -06:00
|
|
|
|
2019-02-18 07:38:42 -06:00
|
|
|
self.env.todo_all_todos.append({
|
|
|
|
'docname': self.env.docname,
|
2019-02-08 11:03:09 -06:00
|
|
|
'lineno': self.lineno,
|
|
|
|
'todo': todo_node.deepcopy(),
|
|
|
|
'target': targetnode,
|
|
|
|
})
|
|
|
|
|
|
|
|
return [targetnode, todo_node]
|
|
|
|
|
|
|
|
|
|
|
|
def purge_todos(app, env, docname):
|
|
|
|
if not hasattr(env, 'todo_all_todos'):
|
|
|
|
return
|
|
|
|
|
|
|
|
env.todo_all_todos = [todo for todo in env.todo_all_todos
|
|
|
|
if todo['docname'] != docname]
|
|
|
|
|
|
|
|
|
2020-07-06 10:55:03 -05:00
|
|
|
def merge_todos(app, env, docnames, other):
|
|
|
|
if not hasattr(env, 'todo_all_todos'):
|
|
|
|
env.todo_all_todos = []
|
|
|
|
if hasattr(other, 'todo_all_todos'):
|
|
|
|
env.todo_all_todos.extend(other.todo_all_todos)
|
|
|
|
|
|
|
|
|
2019-02-08 11:03:09 -06:00
|
|
|
def process_todo_nodes(app, doctree, fromdocname):
|
|
|
|
if not app.config.todo_include_todos:
|
2022-04-21 21:34:31 -05:00
|
|
|
for node in doctree.findall(todo):
|
2019-02-08 11:03:09 -06:00
|
|
|
node.parent.remove(node)
|
|
|
|
|
|
|
|
# Replace all todolist nodes with a list of the collected todos.
|
|
|
|
# Augment each todo with a backlink to the original location.
|
|
|
|
env = app.builder.env
|
|
|
|
|
2020-03-15 04:33:41 -05:00
|
|
|
if not hasattr(env, 'todo_all_todos'):
|
|
|
|
env.todo_all_todos = []
|
|
|
|
|
2022-04-21 21:34:31 -05:00
|
|
|
for node in doctree.findall(todolist):
|
2019-02-08 11:03:09 -06:00
|
|
|
if not app.config.todo_include_todos:
|
|
|
|
node.replace_self([])
|
|
|
|
continue
|
|
|
|
|
|
|
|
content = []
|
|
|
|
|
|
|
|
for todo_info in env.todo_all_todos:
|
|
|
|
para = nodes.paragraph()
|
|
|
|
filename = env.doc2path(todo_info['docname'], base=None)
|
|
|
|
description = (
|
|
|
|
_('(The original entry is located in %s, line %d and can be found ') %
|
|
|
|
(filename, todo_info['lineno']))
|
2022-04-21 21:28:12 -05:00
|
|
|
para += nodes.Text(description)
|
2019-02-08 11:03:09 -06:00
|
|
|
|
|
|
|
# Create a reference
|
|
|
|
newnode = nodes.reference('', '')
|
|
|
|
innernode = nodes.emphasis(_('here'), _('here'))
|
|
|
|
newnode['refdocname'] = todo_info['docname']
|
|
|
|
newnode['refuri'] = app.builder.get_relative_uri(
|
|
|
|
fromdocname, todo_info['docname'])
|
|
|
|
newnode['refuri'] += '#' + todo_info['target']['refid']
|
|
|
|
newnode.append(innernode)
|
|
|
|
para += newnode
|
2022-04-21 21:28:12 -05:00
|
|
|
para += nodes.Text('.)')
|
2019-02-08 11:03:09 -06:00
|
|
|
|
|
|
|
# Insert into the todolist
|
|
|
|
content.append(todo_info['todo'])
|
|
|
|
content.append(para)
|
|
|
|
|
|
|
|
node.replace_self(content)
|
|
|
|
|
|
|
|
|
|
|
|
def setup(app):
|
|
|
|
app.add_config_value('todo_include_todos', False, 'html')
|
|
|
|
|
|
|
|
app.add_node(todolist)
|
|
|
|
app.add_node(todo,
|
|
|
|
html=(visit_todo_node, depart_todo_node),
|
|
|
|
latex=(visit_todo_node, depart_todo_node),
|
|
|
|
text=(visit_todo_node, depart_todo_node))
|
|
|
|
|
|
|
|
app.add_directive('todo', TodoDirective)
|
|
|
|
app.add_directive('todolist', TodolistDirective)
|
|
|
|
app.connect('doctree-resolved', process_todo_nodes)
|
|
|
|
app.connect('env-purge-doc', purge_todos)
|
2020-07-06 10:55:03 -05:00
|
|
|
app.connect('env-merge-info', merge_todos)
|
2019-02-08 11:03:09 -06:00
|
|
|
|
2019-02-11 04:44:49 -06:00
|
|
|
return {
|
|
|
|
'version': '0.1',
|
|
|
|
'parallel_read_safe': True,
|
|
|
|
'parallel_write_safe': True,
|
|
|
|
}
|