179
|
1 |
# -*- coding: utf-8 -*-
|
|
2 |
"""
|
|
3 |
sphinx.ext.todo
|
|
4 |
~~~~~~~~~~~~~~~
|
|
5 |
|
|
6 |
Allow todos to be inserted into your documentation. Inclusion of todos can
|
|
7 |
be switched of by a configuration variable. The todolist directive collects
|
|
8 |
all todos of your project and lists them along with a backlink to the
|
|
9 |
original location.
|
|
10 |
|
|
11 |
:copyright: 2008 Daniel Bültmann.
|
|
12 |
:license: BSD.
|
|
13 |
"""
|
|
14 |
|
|
15 |
from docutils import nodes
|
|
16 |
|
|
17 |
from sphinx.util.compat import make_admonition
|
|
18 |
|
|
19 |
class todo_node(nodes.Admonition, nodes.Element): pass
|
|
20 |
class todolist(nodes.General, nodes.Element): pass
|
|
21 |
|
|
22 |
|
|
23 |
def todo_directive(name, arguments, options, content, lineno,
|
|
24 |
content_offset, block_text, state, state_machine):
|
|
25 |
env = state.document.settings.env
|
|
26 |
|
|
27 |
targetid = "todo-%s" % env.index_num
|
|
28 |
env.index_num += 1
|
|
29 |
targetnode = nodes.target('', '', ids=[targetid])
|
|
30 |
|
|
31 |
ad = make_admonition(todo_node, name, [_('Todo')], options, content, lineno,
|
|
32 |
content_offset, block_text, state, state_machine)
|
|
33 |
|
|
34 |
# Attach a list of all todos to the environment,
|
|
35 |
# the todolist works with the collected todo nodes
|
|
36 |
if not hasattr(env, 'todo_all_todos'):
|
|
37 |
env.todo_all_todos = []
|
|
38 |
env.todo_all_todos.append({
|
|
39 |
'docname': env.docname,
|
|
40 |
'lineno': lineno,
|
|
41 |
'todo': ad[0].deepcopy(),
|
|
42 |
'target': targetnode,
|
|
43 |
})
|
|
44 |
|
|
45 |
return [targetnode] + ad
|
|
46 |
|
|
47 |
|
|
48 |
def todolist_directive(name, arguments, options, content, lineno,
|
|
49 |
content_offset, block_text, state, state_machine):
|
|
50 |
# Simply insert an empty todolist node which will be replaced later
|
|
51 |
# when process_todo_nodes is called
|
|
52 |
return [todolist('')]
|
|
53 |
|
|
54 |
|
|
55 |
def process_todo_nodes(app, doctree, fromdocname):
|
|
56 |
if not app.config['todo_include_todos']:
|
|
57 |
for node in doctree.traverse(todo_node):
|
|
58 |
node.parent.remove(node)
|
|
59 |
|
|
60 |
# Replace all todolist nodes with a list of the collected todos.
|
|
61 |
# Augment each todo with a backlink to the original location.
|
|
62 |
env = app.builder.env
|
|
63 |
|
|
64 |
for node in doctree.traverse(todolist):
|
|
65 |
if not app.config['todo_include_todos']:
|
|
66 |
node.replace_self([])
|
|
67 |
continue
|
|
68 |
|
|
69 |
content = []
|
|
70 |
|
|
71 |
for todo_info in env.todo_all_todos:
|
|
72 |
para = nodes.paragraph()
|
|
73 |
filename = env.doc2path(todo_info['docname'], base=None)
|
|
74 |
description = (
|
|
75 |
_('(The original entry is located in %s, line %d and can be found ') %
|
|
76 |
(filename, todo_info['lineno']))
|
|
77 |
para += nodes.Text(description, description)
|
|
78 |
|
|
79 |
# Create a reference
|
|
80 |
newnode = nodes.reference('', '')
|
|
81 |
innernode = nodes.emphasis(_('here'), _('here'))
|
|
82 |
newnode['refdocname'] = todo_info['docname']
|
|
83 |
newnode['refuri'] = app.builder.get_relative_uri(
|
|
84 |
fromdocname, todo_info['docname'])
|
|
85 |
newnode['refuri'] += '#' + todo_info['target']['refid']
|
|
86 |
newnode.append(innernode)
|
|
87 |
para += newnode
|
|
88 |
para += nodes.Text('.)', '.)')
|
|
89 |
|
|
90 |
# Insert into the todolist
|
|
91 |
content.append(todo_info['todo'])
|
|
92 |
content.append(para)
|
|
93 |
|
|
94 |
node.replace_self(content)
|
|
95 |
|
|
96 |
|
|
97 |
def purge_todos(app, env, docname):
|
|
98 |
if not hasattr(env, 'todo_all_todos'):
|
|
99 |
return
|
|
100 |
env.todo_all_todos = [todo for todo in env.todo_all_todos
|
|
101 |
if todo['docname'] != docname]
|
|
102 |
|
|
103 |
|
|
104 |
def visit_todo_node(self, node):
|
|
105 |
self.visit_admonition(node)
|
|
106 |
|
|
107 |
def depart_todo_node(self, node):
|
|
108 |
self.depart_admonition(node)
|
|
109 |
|
|
110 |
def setup(app):
|
|
111 |
app.add_config_value('todo_include_todos', False, False)
|
|
112 |
|
|
113 |
app.add_node(todolist)
|
|
114 |
app.add_node(todo_node,
|
|
115 |
html=(visit_todo_node, depart_todo_node),
|
|
116 |
latex=(visit_todo_node, depart_todo_node),
|
|
117 |
text=(visit_todo_node, depart_todo_node))
|
|
118 |
|
|
119 |
app.add_directive('todo', todo_directive, 1, (0, 0, 1))
|
|
120 |
app.add_directive('todolist', todolist_directive, 0, (0, 0, 0))
|
|
121 |
app.connect('doctree-resolved', process_todo_nodes)
|
|
122 |
app.connect('env-purge-doc', purge_todos)
|
|
123 |
|