Rename source/ => doc/
[ryppl:doc.git] / doc / boost / todo.py
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: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
12     :license: BSD, see LICENSE for details.
13 """
14
15 from docutils import nodes
16
17 from sphinx.util.compat import Directive, make_admonition
18
19 class todo_node(nodes.Admonition, nodes.Element): pass
20 class todolist(nodes.General, nodes.Element): pass
21
22
23 class Todo(Directive):
24     """
25     A todo entry, displayed (if configured) in the form of an admonition.
26     """
27
28     has_content = True
29     required_arguments = 0
30     optional_arguments = 0
31     final_argument_whitespace = False
32     option_spec = {}
33
34     def run(self):
35         env = self.state.document.settings.env
36
37         targetid = "todo-%s" % env.index_num
38         env.index_num += 1
39         targetnode = nodes.target('', '', ids=[targetid])
40
41         ad = make_admonition(todo_node, self.name, [_('Todo')], self.options,
42                              self.content, self.lineno, self.content_offset,
43                              self.block_text, self.state, self.state_machine)
44
45         # Attach a list of all todos to the environment,
46         # the todolist works with the collected todo nodes
47         if not hasattr(env, 'todo_all_todos'):
48             env.todo_all_todos = []
49         env.todo_all_todos.append({
50             'docname': env.docname,
51             'lineno': self.lineno,
52             'todo': ad[0].deepcopy(),
53             'target': targetnode,
54         })
55
56         return [targetnode] + ad
57
58
59 class TodoList(Directive):
60     """
61     A list of all todo entries.
62     """
63
64     has_content = False
65     required_arguments = 0
66     optional_arguments = 0
67     final_argument_whitespace = False
68     option_spec = {}
69
70     def run(self):
71         # Simply insert an empty todolist node which will be replaced later
72         # when process_todo_nodes is called
73         return [todolist('')]
74
75
76 def process_todo_nodes(app, doctree, fromdocname):
77     if not app.config['todo_include_todos']:
78         for node in doctree.traverse(todo_node):
79             node.parent.remove(node)
80
81     # Replace all todolist nodes with a list of the collected todos.
82     # Augment each todo with a backlink to the original location.
83     env = app.builder.env
84
85     if not hasattr(env, 'todo_all_todos'):
86         env.todo_all_todos = []
87
88     for node in doctree.traverse(todolist):
89         if not app.config['todo_include_todos']:
90             node.replace_self([])
91             continue
92
93         content = []
94
95         for todo_info in env.todo_all_todos:
96             para = nodes.paragraph()
97             filename = env.doc2path(todo_info['docname'], base=None)
98             description = (
99                 _('(The original entry is located in %s, line %d and '
100                   'can be found ') % (filename, todo_info['lineno']))
101             para += nodes.Text(description, description)
102
103             # Create a reference
104             newnode = nodes.reference('', '')
105             innernode = nodes.emphasis(_('here'), _('here'))
106             newnode['refdocname'] = todo_info['docname']
107             newnode['refuri'] = app.builder.get_relative_uri(
108                 fromdocname, todo_info['docname'])
109             newnode['refuri'] += '#' + todo_info['target']['refid']
110             newnode.append(innernode)
111             para += newnode
112             para += nodes.Text('.)', '.)')
113
114             # Insert into the todolist
115             content.append(todo_info['todo'])
116             content.append(para)
117
118         node.replace_self(content)
119
120
121 def purge_todos(app, env, docname):
122     if not hasattr(env, 'todo_all_todos'):
123         return
124     env.todo_all_todos = [todo for todo in env.todo_all_todos
125                           if todo['docname'] != docname]
126
127
128 def visit_todo_node(self, node):
129     self.visit_admonition(node)
130
131 def depart_todo_node(self, node):
132     self.depart_admonition(node)
133
134 def setup(app):
135     app.add_config_value('todo_include_todos', False, False)
136
137     app.add_node(todolist)
138     app.add_node(todo_node,
139                  html=(visit_todo_node, depart_todo_node),
140                  latex=(visit_todo_node, depart_todo_node),
141                  text=(visit_todo_node, depart_todo_node))
142
143     app.add_directive('todo', Todo)
144     app.add_directive('todolist', TodoList)
145     app.connect('doctree-resolved', process_todo_nodes)
146     app.connect('env-purge-doc', purge_todos)
147