summaryrefslogtreecommitdiff
path: root/docutils/docs/howto/rst-directives.txt
blob: 6210940c89ebbbd242878b177e6f375b612e660e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
======================================
 Creating reStructuredText Directives
======================================

:Authors: Dethe Elza, David Goodger
:Contact: delza@enfoldingsystems.com
:Date: $Date$
:Revision: $Revision$
:Copyright: This document has been placed in the public domain.

Directives are the primary extension mechanism of reStructuredText.
This document aims to make the creation of new directives as easy and
understandable as possible.  There are only a couple of
reStructuredText-specific features the developer needs to know to
create a basic directive.

The syntax of directives is detailed in the `reStructuredText Markup
Specification`_, and standard directives are described in
`reStructuredText Directives`_.

Directives are a reStructuredText markup/parser concept.  There is no
"directive" element, no single element that corresponds exactly to the
concept of directives.  Instead, choose the most appropriate elements
from the existing Docutils elements.  Directives build structures
using the existing building blocks.  See `The Docutils Document Tree`_
and the ``docutils.nodes`` module for more about the building blocks
of Docutils documents.

.. _reStructuredText Markup Specification:
   ../ref/rst/restructuredtext.html#directives
.. _reStructuredText Directives: ../ref/rst/directives.html
.. _The Docutils Document Tree: ../ref/doctree.html


.. contents:: Table of Contents


Define the Directive Function
=============================

The directive function does any processing that the directive
requires.  This may require the use of other parts of the
reStructuredText parser.  This is where the directive actually *does*
something.

The directive implementation itself is a callback function whose
signature is as follows::

    def directive_fn(name, arguments, options, content, lineno,
                     content_offset, block_text, state, state_machine):
        code...

    # Set function attributes:
    directive_fn.arguments = ...
    directive_fn.options = ...
    direcitve_fn.content = ...

Function attributes are described below (see `Specify Directive
Arguments, Options, and Content`_).  The directive function parameters
are as follows:

- ``name`` is the directive type or name.

- ``arguments`` is a list of positional arguments, as specified in the
  ``arguments`` function attribute.

- ``options`` is a dictionary mapping option names to values.  The
  options handled by a directive function are specified in the
  ``options`` function attribute.

- ``content`` is a list of strings, the directive content.  Use the
  ``content`` function attribute to allow directive content.

- ``lineno`` is the line number of the first line of the directive.

- ``content_offset`` is the line offset of the first line of the
  content from the beginning of the current input.  Used when
  initiating a nested parse.

- ``block_text`` is a string containing the entire directive.  Include
  it as the content of a literal block in a system message if there is
  a problem.

- ``state`` is the state which called the directive function.

- ``state_machine`` is the state machine which controls the state
  which called the directive function.

Directive functions return a list of nodes which will be inserted into
the document tree at the point where the directive was encountered.
This can be an empty list if there is nothing to insert.  For ordinary
directives, the list must contain body elements or structural
elements.  Some directives are intended specifically for substitution
definitions, and must return a list of ``Text`` nodes and/or inline
elements (suitable for inline insertion, in place of the substitution
reference).  Such directives must verify substitution definition
context, typically using code like this::

    if not isinstance(state, states.SubstitutionDef):
        error = state_machine.reporter.error(
            'Invalid context: the "%s" directive can only be used '
            'within a substitution definition.' % (name),
            nodes.literal_block(block_text, block_text), line=lineno)
        return [error]


Specify Directive Arguments, Options, and Content
=================================================

Function attributes are interpreted by the directive parser (from the
``docutils.parsers.rst.states.Body.run_directive()`` method).  If
unspecified, directive function attributes are assumed to have the
value ``None``.  Three directive function attributes are recognized:

- ``arguments``: A 3-tuple specifying the expected positional
  arguments, or ``None`` if the directive has no arguments.  The 3
  items in the tuple are:

  1. The number of required arguments.
  2. The number of optional arguments.
  3. A boolean, indicating if the final argument may contain whitespace.

  Arguments are normally single whitespace-separated words.  The final
  argument may contain whitespace when indicated by the value 1 (True)
  for the third item in the argument spec tuple.  In this case, the
  final argument in the ``arguments`` parameter to the directive
  function will contain spaces and/or newlines, preserved from the
  input text.

  If the form of the arguments is more complex, specify only one
  argument (either required or optional) and indicate that final
  whitespace is OK (1/True); the client code must do any
  context-sensitive parsing.

- ``options``: The option specification.  ``None`` or an empty dict
  implies no options to parse.

  An option specification must be defined detailing the options
  available to the directive.  An option spec is a mapping of option
  name to conversion function; conversion functions are applied to
  each option value to check validity and convert them to the expected
  type.  Python's built-in conversion functions are often usable for
  this, such as ``int``, ``float``, and ``bool`` (included in Python
  from version 2.2.1).  Other useful conversion functions are included
  in the ``docutils.parsers.rst.directives`` package (in the
  ``__init__.py`` module):

  - ``flag``: For options with no option arguments.  Checks for an
    argument (raises ``ValueError`` if found), returns ``None`` for
    valid flag options.

  - ``unchanged_required``: Returns the text argument, unchanged.
    Raises ``ValueError`` if no argument is found.

  - ``unchanged``: Returns the text argument, unchanged.  Returns an
    empty string ("") if no argument is found.

  - ``path``: Returns the path argument unwrapped (with newlines
    removed).  Raises ``ValueError`` if no argument is found.

  - ``uri``: Returns the URI argument with whitespace removed.  Raises
    ``ValueError`` if no argument is found.

  - ``nonnegative_int``: Checks for a nonnegative integer argument,
    and raises ``ValueError`` if not.

  - ``class_option``: Converts the argument into an ID-compatible
    string and returns it.  Raises ``ValueError`` if no argument is
    found.

  - ``unicode_code``: Convert a Unicode character code to a Unicode
    character.

  - ``single_char_or_unicode``: A single character is returned as-is.
    Unicode characters codes are converted as in ``unicode_code``.

  - ``single_char_or_whitespace_or_unicode``: As with
    ``single_char_or_unicode``, but "tab" and "space" are also
    supported.

  - ``positive_int``: Converts the argument into an integer.  Raises
    ValueError for negative, zero, or non-integer values.

  - ``positive_int_list``: Converts a space- or comma-separated list
    of integers into a Python list of integers.  Raises ValueError for
    non-positive-integer values.

  - ``encoding``: Verfies the encoding argument by lookup.  Raises
    ValueError for unknown encodings.

  A further utility function, ``choice``, is supplied to enable
  options whose argument must be a member of a finite set of possible
  values.  A custom conversion function must be written to use it.
  For example::

      from docutils.parsers.rst import directives

      def yesno(argument):
          return directives.choice(argument, ('yes', 'no'))

  For example, here is an option spec for a directive which allows two
  options, "name" and "value", each with an option argument::

      directive_fn.options = {'name': unchanged, 'value': int}

- ``content``: A boolean; true if content is allowed.  Directive
  functions must handle the case where content is required but not
  present in the input text (an empty content list will be supplied).

The final step of the ``run_directive()`` method is to call the
directive function itself.


Register the Directive
======================

If the directive is a general-use addition to the Docutils core, it
must be registered with the parser and language mappings added:

1. Register the new directive using its canonical name in
   ``docutils/parsers/rst/directives/__init__.py``, in the
   ``_directive_registry`` dictionary.  This allows the
   reStructuredText parser to find and use the directive.

2. Add an entry to the ``directives`` dictionary in
   ``docutils/parsers/rst/languages/en.py`` for the directive, mapping
   the English name to the canonical name (both lowercase).  Usually
   the English name and the canonical name are the same.

3. Update all the other language modules as well.  For languages in
   which you are proficient, please add translations.  For other
   languages, add the English directive name plus "(translation
   required)".

If the directive is application-specific, use the
``register_directive`` function::

    from docutils.parsers.rst import directives
    directives.register_directive(directive_name, directive_function)


Examples
========

For the most direct and accurate information, "Use the Source, Luke!".
All standard directives are documented in `reStructuredText
Directives`_, and the source code implementing them is located in the
``docutils/parsers/rst/directives`` package.  The ``__init__.py``
module contains a mapping of directive name to module & function name.
Several representative directives are described below.


Admonitions
-----------

Admonition directives, such as "note" and "caution", are quite simple.
They have no directive arguments or options.  Admonition directive
content is interpreted as ordinary reStructuredText.  The directive
function simply hands off control to a generic directive function::

   def note(*args):
       return admonition(nodes.note, *args)

   attention.content = 1

Note that the only thing distinguishing the various admonition
directives is the element (node class) generated.  In the code above,
the node class is passed as the first argument to the generic
directive function (early version), where the actual processing takes
place::

   def admonition(node_class, name, arguments, options, content, lineno,
                  content_offset, block_text, state, state_machine):
       text = '\n'.join(content)
       admonition_node = node_class(text)
       if text:
           state.nested_parse(content, content_offset, admonition_node)
           return [admonition_node]
       else:
           warning = state_machine.reporter.warning(
               'The "%s" admonition is empty; content required.'
               % (name), '',
               nodes.literal_block(block_text, block_text), line=lineno)
           return [warning]

Three things are noteworthy in the function above:

1. The ``admonition_node = node_class(text)`` line creates the wrapper
   element, using the class passed in from the initial (stub)
   directive function.

2. The call to ``state.nested_parse()`` is what does the actual
   processing.  It parses the directive content and adds any generated
   elements as child elements of ``admonition_node``.

3. If there was no directive content, a warning is generated and
   returned.  The call to ``state_machine.reporter.warning()``
   includes a literal block containing the entire directive text
   (``block_text``) and the line (``lineno``) of the top of the
   directive.


"image"
-------

The "image" directive is used to insert a picture into a document.
This directive has one argument, the path to the image file, and
supports several options.  There is no directive content.  Here's an
early version of the image directive function::

    def image(name, arguments, options, content, lineno,
              content_offset, block_text, state, state_machine):
        reference = directives.uri(arguments[0])
        options['uri'] = reference
        image_node = nodes.image(block_text, **options)
        return [image_node]

    image.arguments = (1, 0, 1)
    image.options = {'alt': directives.unchanged,
                     'height': directives.nonnegative_int,
                     'width': directives.nonnegative_int,
                     'scale': directives.nonnegative_int,
                     'align': align}

Several things are noteworthy in the code above:

1. The "image" directive requires a single argument, which is allowed
   to contain whitespace (see the argument spec above,
   ``image.arguments = (1, 0, 1)``).  This is to allow for long URLs
   which may span multiple lines.  The first line of the ``image``
   function joins the URL, discarding any embedded whitespace.

2. The reference is added to the ``options`` dictionary under the
   "uri" key; this becomes an attribute of the ``nodes.image`` element
   object.  Any other attributes have already been set explicitly in
   the source text.

3. The "align" option depends on the following definitions (which
   actually occur earlier in the source code)::

       align_values = ('top', 'middle', 'bottom', 'left', 'center',
                       'right')

       def align(argument):
           return directives.choice(argument, align_values)


"contents"
----------

The "contents" directive is used to insert an auto-generated table of
contents (TOC) into a document.  It takes one optional argument, a
title for the TOC.  If no title is specified, a default title is used
instead.  The directive also handles several options.  Here's an early
version of the code::

    def contents(name, arguments, options, content, lineno,
                 content_offset, block_text, state, state_machine):
        """Table of contents."""
        if arguments:
            title_text = arguments[0]
            text_nodes, messages = state.inline_text(title_text, lineno)
            title = nodes.title(title_text, '', *text_nodes)
        else:
            messages = []
            title = None
        pending = nodes.pending(parts.Contents, {'title': title},
                                block_text)
        pending.details.update(options)
        state_machine.document.note_pending(pending)
        return [pending] + messages

    contents.arguments = (0, 1, 1)
    contents.options = {'depth': directives.nonnegative_int,
                        'local': directives.flag,
                        'backlinks': backlinks}

Aspects of note include:

1. The ``contents.arguments = (0, 1, 1)`` function attribute specifies
   a single, *optional* argument.  If no argument is present, the
   ``arguments`` parameter to the directive function will be an empty
   list.

2. If an argument *is* present, its text is passed to
   ``state.inline_text()`` for parsing.  Titles may contain inline
   markup, such as emphasis or inline literals.

3. The table of contents is not generated right away.  Typically, a
   TOC is placed near the beginning of a document, and is a summary or
   outline of the section structure of the document.  The entire
   document must already be processed before a summary can be made.
   This directive leaves a ``nodes.pending`` placeholder element in
   the document tree, marking the position of the TOC and including a
   ``details`` internal attribute containing all the directive
   options, effectively communicating the options forward.  The actual
   table of contents processing is performed by a transform,
   ``docutils.transforms.parts.Contents``, after the rest of the
   document has been parsed.