1 # -*- coding: utf-8 -*-
2 # Author: Jon Waltman <jonathan.waltman@gmail.com>
3 # Copyright: This module is put into the public domain.
6 Texinfo writer for reStructuredText.
8 Texinfo is the official documentation system of the GNU project and
9 can be used to generate multiple output formats. This writer focuses
10 on producing Texinfo that is compiled to Info by the "makeinfo"
15 from docutils
import nodes
, writers
18 \\input texinfo @c -*-texinfo-*-
19 @c %%**start of header
20 @setfilename %(filename)s
21 @documentencoding UTF-8
27 @paragraphindent %(paragraphindent)s
28 @exampleindent %(exampleindent)s
37 @c %%** start of user preamble
39 @c %%** end of user preamble
53 def find_subsections(section
):
54 """Return a list of subsections for the given ``section``."""
56 for child
in section
.children
:
57 if isinstance(child
, nodes
.section
):
60 result
.extend(find_subsections(child
))
65 # Which characters to escape depends on the context. In some cases,
66 # namely menus and node names, it's not possible to escape certain
70 """Return a string with Texinfo command characters escaped."""
71 s
= s
.replace('@', '@@')
72 s
= s
.replace('{', '@{')
73 s
= s
.replace('}', '@}')
74 # Prevent "--" from being converted to an "em dash"
75 # s = s.replace('-', '@w{-}')
79 """Return an escaped string suitable for use as an argument
80 to a Texinfo command."""
82 # Commas are the argument delimeters
83 s
= s
.replace(',', '@comma{}')
84 # Normalize white space
85 s
= ' '.join(s
.split()).strip()
89 """Return an escaped string suitable for node names, menu entries,
91 bad_chars
= ',:.()@{}'
93 s
= s
.replace(bc
, ' ')
94 s
= ' '.join(s
.split()).strip()
98 class Writer(writers
.Writer
):
99 """Texinfo writer for generating Texinfo documents."""
100 supported
= ('texinfo', 'texi')
103 'Texinfo Specific Options',
106 ("Name of the resulting Info file to be created by 'makeinfo'. "
107 "Should probably end with '.info'.",
108 ['--texinfo-filename'],
109 {'default': '', 'metavar': '<file>'}),
111 ('Specify the Info dir entry category.',
112 ['--texinfo-dir-category'],
113 {'default': 'Miscellaneous', 'metavar': '<name>'}),
115 ('The name to use for the Info dir entry. '
116 'If not provided, no entry will be created.',
117 ['--texinfo-dir-entry'],
118 {'default': '', 'metavar': '<name>'}),
120 ('A brief description (one or two lines) to use for the '
122 ['--texinfo-dir-description'],
123 {'default': '', 'metavar': '<desc>'}),
127 settings_defaults
= {}
128 settings_default_overrides
= {'docinfo_xform': 0}
132 visitor_attributes
= ('output', 'fragment')
135 self
.visitor
= visitor
= Translator(self
.document
)
136 self
.document
.walkabout(visitor
)
138 for attr
in self
.visitor_attributes
:
139 setattr(self
, attr
, getattr(visitor
, attr
))
142 class Translator(nodes
.NodeVisitor
):
147 'paragraphindent': 2,
154 def __init__(self
, document
):
155 nodes
.NodeVisitor
.__init
__(self
, document
)
158 self
.written_ids
= set() # node names and anchors in output
159 self
.referenced_ids
= set() # node names and anchors that should
161 self
.node_names
= {} # node name --> node's name to display
162 self
.node_menus
= {} # node name --> node's menu entries
163 self
.rellinks
= {} # node name --> (next, previous, up)
165 self
.collect_node_names()
166 self
.collect_node_menus()
167 self
.collect_rellinks()
171 self
.previous_section
= None
172 self
.section_level
= 0
173 self
.seen_title
= False
174 self
.next_section_targets
= []
175 self
.escape_newlines
= 0
176 self
.curfilestack
= []
179 while self
.referenced_ids
:
180 # Handle xrefs with missing anchors
181 r
= self
.referenced_ids
.pop()
182 if r
not in self
.written_ids
:
183 self
.document
.reporter
.info(
184 "Unknown cross-reference target: `%s'" % r
)
185 self
.add_text('@anchor{%s}@w{%s}\n' % (r
, ' ' * 30))
186 self
.fragment
= ''.join(self
.body
).strip() + '\n'
187 self
.elements
['body'] = self
.fragment
188 self
.output
= TEMPLATE
% self
.elements
193 def init_settings(self
):
194 settings
= self
.settings
= self
.document
.settings
195 elements
= self
.elements
= self
.default_elements
.copy()
197 # if empty, the title is set to the first section title
198 'title': settings
.title
,
199 # if empty, use basename of input file
200 'filename': settings
.texinfo_filename
,
203 title
= elements
['title']
205 title
= self
.document
.next_node(nodes
.title
)
206 title
= (title
and title
.astext()) or '<untitled>'
207 elements
['title'] = escape_id(title
) or '<untitled>'
209 if not elements
['filename']:
210 elements
['filename'] = self
.document
.get('source') or 'untitled'
211 if elements
['filename'][-4:] in ('.txt', '.rst'):
212 elements
['filename'] = elements
['filename'][:-4]
213 elements
['filename'] += '.info'
215 if settings
.texinfo_dir_entry
:
216 elements
['direntry'] = ('@dircategory %s\n'
219 '@end direntry\n') % (
220 escape_id(settings
.texinfo_dir_category
),
221 escape_id(settings
.texinfo_dir_entry
),
222 elements
['filename'],
223 escape_arg(settings
.texinfo_dir_description
))
225 def collect_node_names(self
):
226 """Generates a unique id for each section.
228 Assigns the attribute ``node_name`` to each section."""
229 self
.document
['node_name'] = 'Top'
230 self
.node_names
['Top'] = 'Top'
231 self
.written_ids
.update(('Top', 'top'))
233 for section
in self
.document
.traverse(nodes
.section
):
234 title
= section
.next_node(nodes
.Titular
)
235 name
= (title
and title
.astext()) or '<untitled>'
236 node_id
= name
= escape_id(name
) or '<untitled>'
237 assert node_id
and name
239 while (node_id
+ suffix
).lower() in self
.written_ids
:
241 suffix
= '<%s>' % nth
243 assert node_id
not in self
.node_names
244 assert node_id
not in self
.written_ids
245 assert node_id
.lower() not in self
.written_ids
246 section
['node_name'] = node_id
247 self
.node_names
[node_id
] = name
248 self
.written_ids
.update((node_id
, node_id
.lower()))
250 def collect_node_menus(self
):
251 """Collect the menu entries for each "node" section."""
252 node_menus
= self
.node_menus
253 for node
in ([self
.document
] +
254 self
.document
.traverse(nodes
.section
)):
255 assert 'node_name' in node
and node
['node_name']
256 entries
= tuple(s
['node_name']
257 for s
in find_subsections(node
))
258 node_menus
[node
['node_name']] = entries
259 # Try to find a suitable "Top" node
260 title
= self
.document
.next_node(nodes
.title
)
261 top
= (title
and title
.parent
) or self
.document
262 if not isinstance(top
, (nodes
.document
, nodes
.section
)):
264 if top
is not self
.document
:
265 entries
= node_menus
[top
['node_name']]
266 entries
+= node_menus
['Top'][1:]
267 node_menus
['Top'] = entries
268 del node_menus
[top
['node_name']]
269 top
['node_name'] = 'Top'
271 def collect_rellinks(self
):
272 """Collect the relative links (next, previous, up) for each "node"."""
273 rellinks
= self
.rellinks
274 node_menus
= self
.node_menus
275 for id, entries
in node_menus
.items():
276 rellinks
[id] = ['', '', '']
278 for id, entries
in node_menus
.items():
282 for id, entries
in node_menus
.items():
283 for i
, id in enumerate(entries
):
284 # First child's prev is empty
286 rellinks
[id][1] = entries
[i
-1]
287 # Last child's next is empty
288 if i
!= len(entries
) - 1:
289 rellinks
[id][0] = entries
[i
+1]
290 # Top's next is its first child
292 first
= node_menus
['Top'][0]
296 rellinks
['Top'][0] = first
297 rellinks
[first
][1] = 'Top'
299 def add_text(self
, text
, fresh
=False):
300 """Add some text to the output.
302 Optional argument ``fresh`` means to insert a newline before
303 the text if the last character out was not a newline."""
305 if self
.body
and not self
.body
[-1].endswith('\n'):
306 self
.body
.append('\n')
307 self
.body
.append(text
)
310 """Strip trailing whitespace from the current output."""
311 while self
.body
and not self
.body
[-1].strip():
315 self
.body
[-1] = self
.body
[-1].rstrip()
317 def add_menu_entries(self
, entries
):
318 for entry
in entries
:
319 name
= self
.node_names
[entry
]
321 self
.add_text('* %s::\n' % name
, fresh
=1)
323 self
.add_text('* %s: %s.\n' % (name
, entry
), fresh
=1)
325 def add_menu(self
, section
, master
=False):
326 entries
= self
.node_menus
[section
['node_name']]
329 self
.add_text('\n@menu\n')
330 self
.add_menu_entries(entries
)
332 # Write the "detailed menu"
333 started_detail
= False
334 for entry
in entries
:
335 subentries
= self
.node_menus
[entry
]
338 if not started_detail
:
339 started_detail
= True
340 self
.add_text('\n@detailmenu\n'
341 ' --- The Detailed Node Listing ---\n')
342 self
.add_text('\n%s\n\n' % self
.node_names
[entry
])
343 self
.add_menu_entries(subentries
)
346 self
.add_text('\n@end detailmenu\n')
348 self
.add_text('\n@end menu\n\n')
353 def get_short_id(self
, id):
354 """Return a shorter 'id' associated with ``id``."""
355 # Shorter ids improve paragraph filling in places
356 # that the id is hidden by Emacs.
358 sid
= self
.short_ids
[id]
360 sid
= hex(len(self
.short_ids
))[2:]
361 self
.short_ids
[id] = sid
364 def add_anchor(self
, id, msg_node
=None):
365 # Anchors can be referenced by their original id
366 # or by the generated shortened id
367 id = escape_id(id).lower()
368 ids
= (self
.get_short_id(id), id)
370 if id not in self
.written_ids
:
371 self
.add_text('@anchor{%s}' % id)
372 self
.written_ids
.add(id)
374 def add_xref(self
, ref
, name
, node
):
375 ref
= self
.get_short_id(escape_id(ref
).lower())
376 name
= ' '.join(name
.split()).strip()
377 if not name
or ref
== name
:
378 self
.add_text('@pxref{%s}' % ref
)
380 self
.add_text('@pxref{%s,%s}' % (ref
, name
))
381 self
.referenced_ids
.add(ref
)
385 def visit_document(self
, node
):
387 def depart_document(self
, node
):
390 def visit_Text(self
, node
):
391 s
= escape(node
.astext())
392 if self
.escape_newlines
:
393 s
= s
.replace('\n', ' ')
395 def depart_Text(self
, node
):
398 def visit_section(self
, node
):
399 self
.next_section_targets
.extend(node
.get('ids', []))
400 if not self
.seen_title
:
402 if self
.previous_section
:
403 self
.add_menu(self
.previous_section
)
405 self
.add_menu(self
.document
, master
=True)
407 node_name
= node
['node_name']
408 pointers
= tuple([node_name
] + self
.rellinks
[node_name
])
409 self
.add_text('\n@node %s,%s,%s,%s\n' % pointers
)
410 if node_name
!= node_name
.lower():
411 self
.add_text('@anchor{%s}' % node_name
.lower())
412 for id in self
.next_section_targets
:
413 self
.add_anchor(id, node
)
415 self
.next_section_targets
= []
416 self
.previous_section
= node
417 self
.section_level
+= 1
419 def depart_section(self
, node
):
420 self
.section_level
-= 1
436 def visit_title(self
, node
):
437 if not self
.seen_title
:
441 if isinstance(parent
, nodes
.table
):
443 if isinstance(parent
, nodes
.Admonition
):
445 elif isinstance(parent
, nodes
.sidebar
):
446 self
.visit_rubric(node
)
447 elif isinstance(parent
, nodes
.topic
):
449 elif not isinstance(parent
, nodes
.section
):
450 self
.document
.reporter
.warning(
451 'encountered title node not in section, topic, table, '
452 'admonition or sidebar', base_node
=node
)
453 self
.visit_rubric(node
)
456 heading
= self
.headings
[self
.section_level
]
458 heading
= self
.headings
[-1]
459 self
.add_text('%s ' % heading
, fresh
=1)
461 def depart_title(self
, node
):
462 self
.add_text('', fresh
=1)
464 def visit_rubric(self
, node
):
466 rubric
= self
.rubrics
[self
.section_level
]
468 rubric
= self
.rubrics
[-1]
469 self
.add_text('%s ' % rubric
, fresh
=1)
470 def depart_rubric(self
, node
):
471 self
.add_text('', fresh
=1)
473 def visit_subtitle(self
, node
):
474 self
.add_text('\n\n@noindent\n')
475 def depart_subtitle(self
, node
):
476 self
.add_text('\n\n')
480 def visit_target(self
, node
):
482 self
.add_anchor(node
['ids'][0], node
)
483 elif node
.get('refid'):
484 # Section targets need to go after the start of the section.
485 next
= node
.next_node(ascend
=1, siblings
=1)
486 while isinstance(next
, nodes
.target
):
487 next
= next
.next_node(ascend
=1, siblings
=1)
488 if isinstance(next
, nodes
.section
):
489 self
.next_section_targets
.append(node
['refid'])
491 self
.add_anchor(node
['refid'], node
)
492 elif node
.get('refuri'):
495 self
.document
.reporter
.error("Unknown target type: %r" % node
)
497 def visit_reference(self
, node
):
498 if isinstance(node
.parent
, nodes
.title
):
500 if isinstance(node
[0], nodes
.image
):
502 name
= node
.get('name', node
.astext()).strip()
503 if node
.get('refid'):
504 self
.add_xref(escape_id(node
['refid']),
505 escape_id(name
), node
)
507 if not node
.get('refuri'):
508 self
.document
.reporter
.error("Unknown reference type: %s" % node
)
511 if uri
.startswith('#'):
512 self
.add_xref(escape_id(uri
[1:]), escape_id(name
), node
)
513 elif uri
.startswith('%'):
516 src
, id = uri
[1:].split('#', 1)
518 self
.add_xref(escape_id(id), escape_id(name
), node
)
519 elif uri
.startswith('mailto:'):
520 uri
= escape_arg(uri
[7:])
521 name
= escape_arg(name
)
522 if not name
or name
== uri
:
523 self
.add_text('@email{%s}' % uri
)
525 self
.add_text('@email{%s,%s}' % (uri
, name
))
526 elif uri
.startswith('info:'):
527 uri
= uri
[5:].replace('_', ' ')
528 uri
= escape_arg(uri
)
531 uri
, id = uri
.split('#', 1)
533 name
= escape_id(name
)
535 self
.add_text('@pxref{%s,,,%s}' % (id, uri
))
537 self
.add_text('@pxref{%s,,%s,%s}' % (id, name
, uri
))
539 uri
= escape_arg(uri
)
540 name
= escape_arg(name
)
541 if not name
or uri
== name
:
542 self
.add_text('@indicateurl{%s}' % uri
)
544 self
.add_text('@uref{%s,%s}' % (uri
, name
))
547 def depart_reference(self
, node
):
550 def visit_title_reference(self
, node
):
552 self
.add_text('@cite{%s}' % escape_arg(text
))
554 def visit_title_reference(self
, node
):
559 def visit_paragraph(self
, node
):
560 if 'continued' in node
or isinstance(node
.parent
, nodes
.compound
):
561 self
.add_text('@noindent\n', fresh
=1)
562 def depart_paragraph(self
, node
):
563 self
.add_text('\n\n')
565 def visit_block_quote(self
, node
):
567 self
.add_text('\n\n@quotation\n')
568 def depart_block_quote(self
, node
):
570 self
.add_text('\n@end quotation\n\n')
572 def visit_literal_block(self
, node
):
574 self
.add_text('\n\n@example\n')
575 def depart_literal_block(self
, node
):
577 self
.add_text('\n@end example\n\n'
580 visit_doctest_block
= visit_literal_block
581 depart_doctest_block
= depart_literal_block
583 def visit_line_block(self
, node
):
584 self
.add_text('@display\n', fresh
=1)
585 def depart_line_block(self
, node
):
586 self
.add_text('@end display\n', fresh
=1)
588 def visit_line(self
, node
):
591 self
.escape_newlines
+= 1
592 def depart_line(self
, node
):
593 self
.add_text('@w{ }\n')
594 self
.escape_newlines
-= 1
598 def visit_strong(self
, node
):
599 self
.add_text('@strong{')
600 def depart_strong(self
, node
):
603 def visit_emphasis(self
, node
):
604 self
.add_text('@emph{')
605 def depart_emphasis(self
, node
):
608 def visit_literal(self
, node
):
609 self
.add_text('@code{')
610 def depart_literal(self
, node
):
613 def visit_superscript(self
, node
):
614 self
.add_text('@w{^')
615 def depart_superscript(self
, node
):
618 def visit_subscript(self
, node
):
619 self
.add_text('@w{[')
620 def depart_subscript(self
, node
):
625 def visit_footnote(self
, node
):
626 self
.visit_block_quote(node
)
627 def depart_footnote(self
, node
):
628 self
.depart_block_quote(node
)
630 def visit_footnote_reference(self
, node
):
631 self
.add_text('@w{(')
632 def depart_footnote_reference(self
, node
):
635 visit_citation
= visit_footnote
636 depart_citation
= depart_footnote
638 def visit_citation_reference(self
, node
):
639 self
.add_text('@w{[')
640 def depart_citation_reference(self
, node
):
645 def visit_bullet_list(self
, node
):
646 bullet
= node
.get('bullet', '*')
648 self
.add_text('\n\n@itemize %s\n' % bullet
)
649 def depart_bullet_list(self
, node
):
651 self
.add_text('\n@end itemize\n\n')
653 def visit_enumerated_list(self
, node
):
654 # Doesn't support Roman numerals
655 enum
= node
.get('enumtype', 'arabic')
656 starters
= {'arabic': '',
659 start
= node
.get('start', starters
.get(enum
, ''))
661 self
.add_text('\n\n@enumerate %s\n' % start
)
662 def depart_enumerated_list(self
, node
):
664 self
.add_text('\n@end enumerate\n\n')
666 def visit_list_item(self
, node
):
668 self
.add_text('\n@item\n')
669 def depart_list_item(self
, node
):
674 def visit_option_list(self
, node
):
675 self
.add_text('\n@table @option\n')
676 def depart_option_list(self
, node
):
678 self
.add_text('\n@end table\n\n')
680 def visit_option_list_item(self
, node
):
682 def depart_option_list_item(self
, node
):
685 def visit_option_group(self
, node
):
686 self
.at_item_x
= '@item'
687 def depart_option_group(self
, node
):
690 def visit_option(self
, node
):
691 self
.add_text(self
.at_item_x
+ ' ', fresh
=1)
692 self
.at_item_x
= '@itemx'
693 def depart_option(self
, node
):
696 def visit_option_string(self
, node
):
698 def depart_option_string(self
, node
):
701 def visit_option_argument(self
, node
):
702 self
.add_text(node
.get('delimiter', ' '))
703 def depart_option_argument(self
, node
):
706 def visit_description(self
, node
):
707 self
.add_text('', fresh
=1)
708 def depart_description(self
, node
):
713 def visit_definition_list(self
, node
):
714 self
.add_text('\n@table @asis\n')
715 def depart_definition_list(self
, node
):
717 self
.add_text('\n@end table\n\n')
719 def visit_definition_list_item(self
, node
):
720 self
.at_item_x
= '@item'
721 def depart_definition_list_item(self
, node
):
724 def visit_term(self
, node
):
725 if node
.get('ids') and node
['ids'][0]:
726 self
.add_anchor(node
['ids'][0], node
)
727 self
.add_text(self
.at_item_x
+ ' ', fresh
=1)
728 self
.at_item_x
= '@itemx'
729 def depart_term(self
, node
):
732 def visit_classifier(self
, node
):
734 def depart_classifier(self
, node
):
737 def visit_definition(self
, node
):
738 self
.add_text('', fresh
=1)
739 def depart_definition(self
, node
):
744 def visit_table(self
, node
):
745 self
.entry_sep
= '@item'
746 def depart_table(self
, node
):
748 self
.add_text('\n@end multitable\n\n')
750 def visit_tabular_col_spec(self
, node
):
752 def depart_tabular_col_spec(self
, node
):
755 def visit_colspec(self
, node
):
756 self
.colwidths
.append(node
['colwidth'])
757 if len(self
.colwidths
) != self
.n_cols
:
759 self
.add_text('@multitable ', fresh
=1)
760 for i
, n
in enumerate(self
.colwidths
):
761 self
.add_text('{%s} ' %('x' * (n
+2)))
762 def depart_colspec(self
, node
):
765 def visit_tgroup(self
, node
):
767 self
.n_cols
= node
['cols']
768 def depart_tgroup(self
, node
):
771 def visit_thead(self
, node
):
772 self
.entry_sep
= '@headitem'
773 def depart_thead(self
, node
):
776 def visit_tbody(self
, node
):
778 def depart_tbody(self
, node
):
781 def visit_row(self
, node
):
783 def depart_row(self
, node
):
784 self
.entry_sep
= '@item'
786 def visit_entry(self
, node
):
788 self
.add_text('\n%s ' % self
.entry_sep
)
789 self
.entry_sep
= '@tab'
790 def depart_entry(self
, node
):
791 for i
in xrange(node
.get('morecols', 0)):
792 self
.add_text('@tab\n', fresh
=1)
793 self
.add_text('', fresh
=1)
797 def visit_field_list(self
, node
):
798 self
.add_text('\n@itemize @w\n')
799 def depart_field_list(self
, node
):
801 self
.add_text('\n@end itemize\n\n')
803 def visit_field(self
, node
):
804 if not isinstance(node
.parent
, nodes
.field_list
):
805 self
.visit_field_list(None)
806 def depart_field(self
, node
):
807 if not isinstance(node
.parent
, nodes
.field_list
):
808 self
.depart_field_list(None)
810 def visit_field_name(self
, node
):
811 self
.add_text('@item ', fresh
=1)
812 def depart_field_name(self
, node
):
815 def visit_field_body(self
, node
):
816 self
.add_text('', fresh
=1)
817 def depart_field_body(self
, node
):
822 def visit_admonition(self
, node
):
823 title
= escape(node
[0].astext())
824 self
.add_text('\n@cartouche\n'
825 '@quotation %s\n' % title
)
826 def depart_admonition(self
, node
):
828 self
.add_text('\n@end quotation\n'
829 '@end cartouche\n\n')
831 def _make_visit_admonition(typ
):
832 def visit(self
, node
):
834 self
.add_text('\n@cartouche\n'
835 '@quotation %s\n' % title
)
838 visit_attention
= _make_visit_admonition('Attention')
839 visit_caution
= _make_visit_admonition('Caution')
840 visit_danger
= _make_visit_admonition('Danger')
841 visit_error
= _make_visit_admonition('Error')
842 visit_important
= _make_visit_admonition('Important')
843 visit_note
= _make_visit_admonition('Note')
844 visit_tip
= _make_visit_admonition('Tip')
845 visit_hint
= _make_visit_admonition('Hint')
846 visit_warning
= _make_visit_admonition('Warning')
848 depart_attention
= depart_admonition
849 depart_caution
= depart_admonition
850 depart_danger
= depart_admonition
851 depart_error
= depart_admonition
852 depart_important
= depart_admonition
853 depart_note
= depart_admonition
854 depart_tip
= depart_admonition
855 depart_hint
= depart_admonition
856 depart_warning
= depart_admonition
860 def visit_docinfo(self
, node
):
864 def visit_topic(self
, node
):
865 # Ignore TOC's since we have to have a "menu" anyway
866 if 'contents' in node
.get('classes', []):
869 self
.visit_rubric(title
)
870 self
.add_text('%s\n' % escape(title
.astext()))
871 self
.visit_block_quote(node
)
872 def depart_topic(self
, node
):
873 self
.depart_block_quote(node
)
875 def visit_generated(self
, node
):
877 def depart_generated(self
, node
):
880 def visit_transition(self
, node
):
881 self
.add_text('\n\n@noindent\n'
883 '@noindent\n' % ('_' * 70))
884 def depart_transition(self
, node
):
887 def visit_attribution(self
, node
):
888 self
.add_text('@flushright\n', fresh
=1)
889 def depart_attribution(self
, node
):
890 self
.add_text('@end flushright\n', fresh
=1)
892 def visit_raw(self
, node
):
893 format
= node
.get('format', '').split()
894 if 'texinfo' in format
or 'texi' in format
:
895 self
.add_text(node
.astext())
897 def depart_raw(self
, node
):
900 def visit_figure(self
, node
):
901 self
.add_text('\n@float Figure\n')
902 def depart_figure(self
, node
):
904 self
.add_text('\n@end float\n\n')
906 def visit_caption(self
, node
):
907 if not isinstance(node
.parent
, nodes
.figure
):
908 self
.document
.reporter
.warning('Caption not inside a figure.',
911 self
.add_text('@caption{', fresh
=1)
912 def depart_caption(self
, node
):
913 if isinstance(node
.parent
, nodes
.figure
):
917 def visit_image(self
, node
):
918 self
.add_text('@w{[image]}')
920 def depart_image(self
, node
):
923 def visit_compound(self
, node
):
925 def depart_compound(self
, node
):
928 def visit_sidebar(self
, node
):
930 def depart_sidebar(self
, node
):
933 def visit_label(self
, node
):
934 self
.add_text('@w{(')
935 def depart_label(self
, node
):
938 def visit_legend(self
, node
):
940 def depart_legend(self
, node
):
943 def visit_substitution_reference(self
, node
):
945 def depart_substitution_reference(self
, node
):
948 def visit_substitution_definition(self
, node
):
950 def depart_substitution_definition(self
, node
):
953 def visit_system_message(self
, node
):
954 self
.add_text('\n@format\n'
955 '---------- SYSTEM MESSAGE -----------\n')
956 def depart_system_message(self
, node
):
958 self
.add_text('\n------------------------------------\n'
961 def visit_comment(self
, node
):
962 for line
in node
.astext().splitlines():
963 self
.add_text('@c %s\n' % line
, fresh
=1)
965 def depart_comment(self
, node
):
968 def visit_problematic(self
, node
):
970 def depart_problematic(self
, node
):
973 def unimplemented_visit(self
, node
):
974 self
.document
.reporter
.error("Unimplemented node type: `%s'"
975 % node
.__class
__.__name
__, base_node
=node
)
977 def unknown_visit(self
, node
):
978 self
.document
.reporter
.error("Unknown node type: `%s'"
979 % node
.__class
__.__name
__, base_node
=node
)
980 def unknown_departure(self
, node
):