# -*- coding: utf-8 -*-""" sphinx.ext.todo ~~~~~~~~~~~~~~~ Allow todos to be inserted into your documentation. Inclusion of todos can be switched of by a configuration variable. The todolist directive collects all todos of your project and lists them along with a backlink to the original location. :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details."""fromdocutilsimportnodesfromsphinx.localeimport_fromsphinx.environmentimportNoUrifromsphinx.util.nodesimportset_source_infofromsphinx.util.compatimportDirective,make_admonitionclasstodo_node(nodes.Admonition,nodes.Element):passclasstodolist(nodes.General,nodes.Element):passclassTodo(Directive):""" A todo entry, displayed (if configured) in the form of an admonition. """has_content=Truerequired_arguments=0optional_arguments=0final_argument_whitespace=Falseoption_spec={}defrun(self):env=self.state.document.settings.envtargetid='index-%s'%env.new_serialno('index')targetnode=nodes.target('','',ids=[targetid])ad=make_admonition(todo_node,self.name,[_('Todo')],self.options,self.content,self.lineno,self.content_offset,self.block_text,self.state,self.state_machine)set_source_info(self,ad[0])return[targetnode]+addefprocess_todos(app,doctree):# collect all todos in the environment# this is not done in the directive itself because it some transformations# must have already been run, e.g. substitutionsenv=app.builder.envifnothasattr(env,'todo_all_todos'):env.todo_all_todos=[]fornodeindoctree.traverse(todo_node):try:targetnode=node.parent[node.parent.index(node)-1]ifnotisinstance(targetnode,nodes.target):raiseIndexErrorexceptIndexError:targetnode=Noneenv.todo_all_todos.append({'docname':env.docname,'source':node.sourceorenv.doc2path(env.docname),'lineno':node.line,'todo':node.deepcopy(),'target':targetnode,})classTodoList(Directive):""" A list of all todo entries. """has_content=Falserequired_arguments=0optional_arguments=0final_argument_whitespace=Falseoption_spec={}defrun(self):# Simply insert an empty todolist node which will be replaced later# when process_todo_nodes is calledreturn[todolist('')]defprocess_todo_nodes(app,doctree,fromdocname):ifnotapp.config['todo_include_todos']:fornodeindoctree.traverse(todo_node):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.envifnothasattr(env,'todo_all_todos'):env.todo_all_todos=[]fornodeindoctree.traverse(todolist):ifnotapp.config['todo_include_todos']:node.replace_self([])continuecontent=[]fortodo_infoinenv.todo_all_todos:para=nodes.paragraph(classes=['todo-source'])description=_('(The <<original entry>> is located in '' %s, line %d.)')% \
(todo_info['source'],todo_info['lineno'])desc1=description[:description.find('<<')]desc2=description[description.find('>>')+2:]para+=nodes.Text(desc1,desc1)# Create a referencenewnode=nodes.reference('','',internal=True)innernode=nodes.emphasis(_('original entry'),_('original entry'))try:newnode['refuri']=app.builder.get_relative_uri(fromdocname,todo_info['docname'])newnode['refuri']+='#'+todo_info['target']['refid']exceptNoUri:# ignore if no URI can be determined, e.g. for LaTeX outputpassnewnode.append(innernode)para+=newnodepara+=nodes.Text(desc2,desc2)# (Recursively) resolve references in the todo contenttodo_entry=todo_info['todo']env.resolve_references(todo_entry,todo_info['docname'],app.builder)# Insert into the todolistcontent.append(todo_entry)content.append(para)node.replace_self(content)defpurge_todos(app,env,docname):ifnothasattr(env,'todo_all_todos'):returnenv.todo_all_todos=[todofortodoinenv.todo_all_todosiftodo['docname']!=docname]defvisit_todo_node(self,node):self.visit_admonition(node)defdepart_todo_node(self,node):self.depart_admonition(node)defsetup(app):app.add_config_value('todo_include_todos',False,False)app.add_node(todolist)app.add_node(todo_node,html=(visit_todo_node,depart_todo_node),latex=(visit_todo_node,depart_todo_node),text=(visit_todo_node,depart_todo_node),man=(visit_todo_node,depart_todo_node))app.add_directive('todo',Todo)app.add_directive('todolist',TodoList)app.connect('doctree-read',process_todos)app.connect('doctree-resolved',process_todo_nodes)app.connect('env-purge-doc',purge_todos)