|
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 |