summaryrefslogtreecommitdiff
path: root/doc/ext/tutorial.rst
diff options
context:
space:
mode:
Diffstat (limited to 'doc/ext/tutorial.rst')
-rw-r--r--doc/ext/tutorial.rst113
1 files changed, 70 insertions, 43 deletions
diff --git a/doc/ext/tutorial.rst b/doc/ext/tutorial.rst
index ae9b7a77..c44748d2 100644
--- a/doc/ext/tutorial.rst
+++ b/doc/ext/tutorial.rst
@@ -109,8 +109,8 @@ new Python module called :file:`todo.py` and add the setup function::
latex=(visit_todo_node, depart_todo_node),
text=(visit_todo_node, depart_todo_node))
- app.add_directive('todo', todo_directive, 1, (0, 0, 1))
- app.add_directive('todolist', todolist_directive, 0, (0, 0, 0))
+ app.add_directive('todo', TodoDirective)
+ app.add_directive('todolist', TodolistDirective)
app.connect('doctree-resolved', process_todo_nodes)
app.connect('env-purge-doc', purge_todos)
@@ -132,9 +132,7 @@ the individual calls do is the following:
We need to create the two node classes ``todo`` and ``todolist`` later.
-* :meth:`~Sphinx.add_directive` adds a new *directive*, given by name, handler
- function and two arguments that specify if the directive has content and how
- many arguments it accepts.
+* :meth:`~Sphinx.add_directive` adds a new *directive*, given by name and class.
The handler functions are created later.
@@ -158,7 +156,7 @@ Let's start with the node classes::
def visit_todo_node(self, node):
self.visit_admonition(node)
-
+
def depart_todo_node(self, node):
self.depart_admonition(node)
@@ -168,17 +166,25 @@ docutils classes defined in :mod:`docutils.nodes`. ``todo`` inherits from
is just a "general" node.
-The Directive Handlers
-----------------------
+The Directive Classes
+---------------------
-A directive handler is a function with a host of arguments, covered in detail in
-the docutils documentation. It must return a list of nodes.
+A directive class is a class deriving usually from
+``docutils.parsers.rst.Directive``. Since the class-based directive interface
+doesn't exist yet in Docutils 0.4, Sphinx has another base class called
+``sphinx.util.compat.Directive`` that you can derive your directive from, and it
+will work with both Docutils 0.4 and 0.5 upwards. The directive interface is
+covered in detail in the docutils documentation; the important thing is that the
+class has a method ``run`` that returns a list of nodes.
The ``todolist`` directive is quite simple::
- def todolist_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- return [todolist('')]
+ from sphinx.util.compat import Directive
+
+ class TodolistDirective(Directive):
+
+ def run(self):
+ return [todolist('')]
An instance of our ``todolist`` node class is created and returned. The
todolist directive has neither content nor arguments that need to be handled.
@@ -187,30 +193,35 @@ The ``todo`` directive function looks like this::
from sphinx.util.compat import make_admonition
- def todo_directive(name, arguments, options, content, lineno,
- content_offset, block_text, state, state_machine):
- env = state.document.settings.env
-
- targetid = "todo-%s" % env.index_num
- env.index_num += 1
- targetnode = nodes.target('', '', ids=[targetid])
-
- ad = make_admonition(todo, name, [_('Todo')], options, content, lineno,
- content_offset, block_text, state, state_machine)
-
- if not hasattr(env, 'todo_all_todos'):
- env.todo_all_todos = []
- env.todo_all_todos.append({
- 'docname': env.docname,
- 'lineno': lineno,
- 'todo': ad[0].deepcopy(),
- 'target': targetnode,
- })
-
- return [targetnode] + ad
+ class TodoDirective(Directive):
+
+ # this enables content in the directive
+ has_content = True
+
+ def run(self):
+ env = self.state.document.settings.env
+
+ targetid = "todo-%s" % env.index_num
+ env.index_num += 1
+ targetnode = nodes.target('', '', ids=[targetid])
+
+ ad = make_admonition(todo, self.name, [_('Todo')], self.options,
+ self.content, self.lineno, self.content_offset,
+ self.block_text, self.state, self.state_machine)
+
+ if not hasattr(env, 'todo_all_todos'):
+ env.todo_all_todos = []
+ env.todo_all_todos.append({
+ 'docname': env.docname,
+ 'lineno': self.lineno,
+ 'todo': ad[0].deepcopy(),
+ 'target': targetnode,
+ })
+
+ return [targetnode] + ad
Several important things are covered here. First, as you can see, you can refer
-to the build environment instance using ``state.document.settings.env``.
+to the build environment instance using ``self.state.document.settings.env``.
Then, to act as a link target (from the todolist), the todo directive needs to
return a target node in addition to the todo node. The target ID (in HTML, this
@@ -236,6 +247,22 @@ node.
In the last line, the nodes that should be put into the doctree are returned:
the target node and the admonition node.
+The node structure that the directive returns looks like this::
+
+ +--------------------+
+ | target node |
+ +--------------------+
+ +--------------------+
+ | todo node |
+ +--------------------+
+ \__+--------------------+
+ | admonition title |
+ +--------------------+
+ | paragraph |
+ +--------------------+
+ | ... |
+ +--------------------+
+
The Event Handlers
------------------
@@ -262,20 +289,20 @@ emitted at the end of phase 3 and allows custom resolving to be done::
def process_todo_nodes(app, doctree, fromdocname):
if not app.config.todo_include_todos:
- for node in doctree.traverse(todo_node):
+ for node in doctree.traverse(todo):
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
-
+
for node in doctree.traverse(todolist):
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)
@@ -283,7 +310,7 @@ emitted at the end of phase 3 and allows custom resolving to be done::
_('(The original entry is located in %s, line %d and can be found ') %
(filename, todo_info['lineno']))
para += nodes.Text(description, description)
-
+
# Create a reference
newnode = nodes.reference('', '')
innernode = nodes.emphasis(_('here'), _('here'))
@@ -294,11 +321,11 @@ emitted at the end of phase 3 and allows custom resolving to be done::
newnode.append(innernode)
para += newnode
para += nodes.Text('.)', '.)')
-
+
# Insert into the todolist
content.append(todo_info['todo'])
content.append(para)
-
+
node.replace_self(content)
It is a bit more involved. If our new "todo_include_todos" config value is