File: Synopsis/Formatters/DocBook/Markup/RST.py 1
2
3
4
5
6
7
8
9from Synopsis.Formatters.DocBook.Markup import *
10from docutils import writers, nodes, languages
11from docutils.nodes import *
12from docutils.core import *
13from docutils.parsers.rst import roles
14import string, re, StringIO
15
16class Writer(writers.Writer):
17
18 settings_spec = (
19 'DocBook-Specific Options',
20 None,
21 (('Set DocBook document type. '
22 'Choices are "article", "book", and "chapter". '
23 'Default is "article".',
24 ['--doctype'],
25 {'default': 'article',
26 'metavar': '<name>',
27 'type': 'choice',
28 'choices': ('article', 'book', 'chapter',)
29 }
30 ),
31 )
32 )
33
34
35 """DocBook does its own section numbering"""
36 settings_default_overrides = {'enable_section_numbering': 0}
37
38 output = None
39 """Final translated form of `document`."""
40
41 def translate(self):
42 visitor = DocBookTranslator(self.document)
43 self.document.walkabout(visitor)
44 self.output = visitor.astext()
45
46
47class DocBookTranslator(nodes.NodeVisitor):
48
49 def __init__(self, document):
50 nodes.NodeVisitor.__init__(self, document)
51 self.language = languages.get_language(
52 document.settings.language_code)
53 self.doctype = document.settings.doctype
54 self.body = []
55 self.section = 0
56 self.context = []
57 self.colnames = []
58 self.footnotes = {}
59 self.footnote_map = {}
60 self.docinfo = []
61 self.title = ''
62 self.subtitle = ''
63
64 def astext(self):
65 return ''.join(self.docinfo
66 + self.body)
67
68 def encode(self, text):
69 """Encode special characters in `text` & return."""
70
71
72 text = text.replace("&", "&")
73 text = text.replace("<", "<")
74 text = text.replace('"', """)
75 text = text.replace(">", ">")
76 return text
77
78 def encodeattr(self, text):
79 """Encode attributes characters > 128 as &#XXX;"""
80 buff = []
81 for c in text:
82 if ord(c) >= 128:
83 buff.append('&#%d;' % ord(c))
84 else:
85 buff.append(c)
86 return ''.join(buff)
87
88 def rearrange_footnotes(self):
89 """
90 Replaces ``foonote_reference`` placeholders with
91 ``footnote`` element content as DocBook and reST
92 handle footnotes differently.
93
94 DocBook defines footnotes inline, whereas they
95 may be anywere in reST. This function replaces the
96 first instance of a ``footnote_reference`` with
97 the ``footnote`` element itself, and later
98 references of the same a footnote with
99 ``footnoteref`` elements.
100 """
101 for (footnote_id,refs) in self.footnote_map.items():
102 ref_id, context, pos = refs[0]
103 context[pos] = ''.join(self.footnotes[footnote_id])
104 for ref_id, context, pos in refs[1:]:
105 context[pos] = '<footnoteref linkend="%s"/>'% (footnote_id,)
106
107 def attval(self, text,
108 transtable=string.maketrans('\n\r\t\v\f', ' ')):
109 """Cleanse, encode, and return attribute value text."""
110 return self.encode(text.translate(transtable))
111
112 def starttag(self, node, tagname, suffix='\n', infix='', **attributes):
113 """
114 Construct and return a start tag given a node
115 (id & class attributes are extracted), tag name,
116 and optional attributes.
117 """
118 atts = {}
119 for (name, value) in attributes.items():
120 atts[name.lower()] = value
121
122 for att in ('id',):
123 if node.has_key(att):
124 atts[att] = node[att]
125
126 attlist = atts.items()
127 attlist.sort()
128 parts = [tagname.lower()]
129 for name, value in attlist:
130 if value is None:
131
132
133
134 parts.append(name.lower())
135 elif isinstance(value, list):
136 values = [str(v) for v in value]
137 parts.append('%s="%s"' % (name.lower(),
138 self.attval(' '.join(values))))
139 else:
140 name = self.encodeattr(name.lower())
141 value = str(self.encodeattr(unicode(value)))
142 value = self.attval(value)
143 parts.append('%s="%s"' % (name,value))
144
145 return '<%s%s>%s' % (' '.join(parts), infix, suffix)
146
147 def emptytag(self, node, tagname, suffix='\n', **attributes):
148 """Construct and return an XML-compatible empty tag."""
149 return self.starttag(node, tagname, suffix, infix=' /', **attributes)
150
151 def visit_Text(self, node):
152 self.body.append(self.encode(node.astext()))
153
154 def depart_Text(self, node):
155 pass
156
157 def visit_address(self, node):
158
159 pass
160
161 def depart_address(self, node):
162
163 pass
164
165 def visit_admonition(self, node, name=''):
166 self.body.append(self.starttag(node, 'note'))
167
168 def depart_admonition(self, node=None):
169 self.body.append('</note>\n')
170
171 def visit_attention(self, node):
172 self.body.append(self.starttag(node, 'note'))
173 self.body.append('\n<title>%s</title>\n'
174 % (self.language.labels[node.tagname],))
175
176 def depart_attention(self, node):
177 self.body.append('</note>\n')
178
179 def visit_attribution(self, node):
180
181 if isinstance(node.parent, nodes.block_quote):
182 raise nodes.SkipNode
183 self.body.append(self.starttag(node, 'attribution', ''))
184
185 def depart_attribution(self, node):
186
187 if not isinstance(node.parent, nodes.block_quote):
188 self.body.append('</attribution>\n')
189
190
191 def visit_author(self, node):
192 raise nodes.SkipNode
193
194
195 def visit_authors(self, node):
196 raise nodes.SkipNode
197
198 def visit_block_quote(self, node):
199 self.body.append(self.starttag(node, 'blockquote'))
200 if isinstance(node[-1], nodes.attribution):
201 self.body.append('<attribution>%s</attribution>\n' % node[-1].astext())
202
203 def depart_block_quote(self, node):
204 self.body.append('</blockquote>\n')
205
206 def visit_bullet_list(self, node):
207 self.body.append(self.starttag(node, 'itemizedlist'))
208
209 def depart_bullet_list(self, node):
210 self.body.append('</itemizedlist>\n')
211
212 def visit_caption(self, node):
213
214
215 self.body.append(self.starttag(node, 'para'))
216
217 def depart_caption(self, node):
218 self.body.append('</para>')
219
220 def visit_caution(self, node):
221 self.body.append(self.starttag(node, 'caution'))
222 self.body.append('\n<title>%s</title>\n'
223 % (self.language.labels[node.tagname],))
224
225 def depart_caution(self, node):
226 self.body.append('</caution>\n')
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 def visit_citation(self, node):
253 self.visit_footnote(node)
254
255 def depart_citation(self, node):
256 self.depart_footnote(node)
257
258 def visit_citation_reference(self, node):
259 self.visit_footnote_reference(node)
260
261 def depart_citation_reference(self, node):
262
263 pass
264
265 def visit_classifier(self, node):
266 self.body.append(self.starttag(node, 'type'))
267
268 def depart_classifier(self, node):
269 self.body.append('</type>\n')
270
271 def visit_colspec(self, node):
272 self.colnames.append('col_%d' % (len(self.colnames) + 1,))
273 atts = {'colname': self.colnames[-1]}
274 self.body.append(self.emptytag(node, 'colspec', **atts))
275
276 def depart_colspec(self, node):
277 pass
278
279 def visit_comment(self, node, sub=re.compile('-(?=-)').sub):
280 """Escape double-dashes in comment text."""
281 self.body.append('<!-- %s -->\n' % sub('- ', node.astext()))
282 raise nodes.SkipNode
283
284
285 def visit_contact(self, node):
286 raise nodes.SkipNode
287
288
289 def visit_copyright(self, node):
290 raise nodes.SkipNode
291
292 def visit_danger(self, node):
293 self.body.append(self.starttag(node, 'caution'))
294 self.body.append('\n<title>%s</title>\n'
295 % (self.language.labels[node.tagname],))
296
297 def depart_danger(self, node):
298 self.body.append('</caution>\n')
299
300
301 def visit_date(self, node):
302 raise nodes.SkipNode
303
304 def visit_decoration(self, node):
305 pass
306 def depart_decoration(self, node):
307 pass
308
309 def visit_definition(self, node):
310
311 self.body.append('</term>\n')
312 self.body.append(self.starttag(node, 'listitem'))
313
314 def depart_definition(self, node):
315 self.body.append('</listitem>\n')
316
317 def visit_definition_list(self, node):
318 self.body.append(self.starttag(node, 'variablelist'))
319
320 def depart_definition_list(self, node):
321 self.body.append('</variablelist>\n')
322
323 def visit_definition_list_item(self, node):
324 self.body.append(self.starttag(node, 'varlistentry'))
325
326 def depart_definition_list_item(self, node):
327 self.body.append('</varlistentry>\n')
328
329 def visit_description(self, node):
330 self.body.append(self.starttag(node, 'entry'))
331
332 def depart_description(self, node):
333 self.body.append('</entry>\n')
334
335 def visit_docinfo(self, node):
336 """
337 Collects all docinfo elements for the document.
338
339 Since reST's bibliography elements don't map very
340 cleanly to DocBook, rather than maintain state and
341 check dependencies within the different visitor
342 fuctions all processing of bibliography elements
343 is dont within this function.
344
345 .. NOTE:: Skips processing of all child nodes as
346 everything should be collected here.
347 """
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363 docinfo = ['<%sinfo>\n' % self.doctype]
364
365 address = ''
366 authors = []
367 author = ''
368 contact = ''
369 date = ''
370 legalnotice = ''
371 orgname = ''
372 releaseinfo = ''
373 revision,version = '',''
374
375 docinfo.append('<title>%s</title>\n' % self.title)
376 if self.subtitle:
377 docinfo.append('<subtitle>%s</subtitle>\n' % self.subtitle)
378
379 for n in node:
380 if isinstance(n, nodes.address):
381 address = n.astext()
382 elif isinstance(n, nodes.author):
383 author = n.astext()
384 elif isinstance(n, nodes.authors):
385 for a in n:
386 authors.append(a.astext())
387 elif isinstance(n, nodes.contact):
388 contact = n.astext()
389 elif isinstance(n, nodes.copyright):
390 legalnotice = n.astext()
391 elif isinstance(n, nodes.date):
392 date = n.astext()
393 elif isinstance(n, nodes.organization):
394 orgname = n.astext()
395 elif isinstance(n, nodes.revision):
396
397 revision = 'Revision ' + n.astext()
398 elif isinstance(n, nodes.status):
399 releaseinfo = n.astext()
400 elif isinstance(n, nodes.version):
401
402 version = 'Version ' + n.astext()
403 elif isinstance(n, nodes.field):
404
405 import sys
406 print >> sys.stderr, "I don't do 'field' yet"
407 print n.astext()
408
409
410 else:
411 print dir(n)
412 print n.astext()
413 raise self.unimplemented_visit(n)
414
415
416
417
418 if author:
419 docinfo.append('<author>\n')
420 docinfo.append('<othername>%s</othername>\n' % author)
421 if contact:
422 docinfo.append('<email>%s</email>\n' % contact)
423 docinfo.append('</author>\n')
424
425 if authors:
426 docinfo.append('<authorgroup>\n')
427 for name in authors:
428 docinfo.append(
429 '<author><othername>%s</othername></author>\n' % name)
430 docinfo.append('</authorgroup>\n')
431
432 if revision or version:
433 edition = version
434 if edition and revision:
435 edition += ', ' + revision
436 elif revision:
437 edition = revision
438 docinfo.append('<edition>%s</edition>\n' % edition)
439
440 if date:
441 docinfo.append('<date>%s</date>\n' % date)
442
443 if orgname:
444 docinfo.append('<orgname>%s</orgname>\n' % orgname)
445
446 if releaseinfo:
447 docinfo.append('<releaseinfo>%s</releaseinfo>\n' % releaseinfo)
448
449 if legalnotice:
450 docinfo.append('<legalnotice>\n')
451 docinfo.append('<para>%s</para>\n' % legalnotice)
452 docinfo.append('</legalnotice>\n')
453
454 if address:
455 docinfo.append('<address xml:space="preserve">' +
456 address + '</address>\n')
457
458 if len(docinfo) > 1:
459 docinfo.append('</%sinfo>\n' % self.doctype)
460
461 self.docinfo = docinfo
462
463 raise nodes.SkipChildren
464
465 def depart_docinfo(self, node):
466 pass
467
468 def visit_doctest_block(self, node):
469 self.body.append('<informalexample>\n')
470 self.body.append(self.starttag(node, 'programlisting'))
471
472 def depart_doctest_block(self, node):
473 self.body.append('</programlisting>\n')
474 self.body.append('</informalexample>\n')
475
476 def visit_document(self, node):
477 pass
478
479 def depart_document(self, node):
480 self.rearrange_footnotes()
481
482 def visit_emphasis(self, node):
483 self.body.append('<emphasis>')
484
485 def depart_emphasis(self, node):
486 self.body.append('</emphasis>')
487
488 def visit_entry(self, node):
489 tagname = 'entry'
490 atts = {}
491 if node.has_key('morerows'):
492 atts['morerows'] = node['morerows']
493 if node.has_key('morecols'):
494 atts['namest'] = self.colnames[self.entry_level]
495 atts['nameend'] = self.colnames[self.entry_level+ node['morecols']]
496 self.entry_level += 1
497 self.body.append(self.starttag(node, tagname, '', **atts))
498
499 def depart_entry(self, node):
500 self.body.append('</entry>\n')
501
502 def visit_enumerated_list(self, node):
503
504 self.body.append(self.starttag(node, 'orderedlist'))
505
506 def depart_enumerated_list(self, node):
507 self.body.append('</orderedlist>\n')
508
509 def visit_error(self, node):
510 self.body.append(self.starttag(node, 'caution'))
511 self.body.append('\n<title>%s</title>\n'
512 % (self.language.labels[node.tagname],))
513
514 def depart_error(self, node):
515 self.body.append('</caution>\n')
516
517
518 def visit_field(self, node):
519 self.body.append(self.starttag(node, 'varlistentry'))
520
521 def depart_field(self, node):
522 self.body.append('</varlistentry>\n')
523
524
525 def visit_field_argument(self, node):
526 self.body.append(' ')
527
528 def depart_field_argument(self, node):
529 pass
530
531 def visit_field_body(self, node):
532
533
534
535 self.body.append(self.context.pop())
536 self.body.append(self.starttag(node, 'listitem'))
537
538 def depart_field_body(self, node):
539 self.body.append('</listitem>\n')
540
541 def visit_field_list(self, node):
542 self.body.append(self.starttag(node, 'variablelist'))
543
544 def depart_field_list(self, node):
545 self.body.append('</variablelist>\n')
546
547 def visit_field_name(self, node):
548 self.body.append(self.starttag(node, 'term'))
549
550
551 self.context.append('</term>\n')
552
553 def depart_field_name(self, node):
554 pass
555
556 def visit_figure(self, node):
557 self.body.append(self.starttag(node, 'informalfigure'))
558 self.body.append('<blockquote>')
559
560 def depart_figure(self, node):
561 self.body.append('</blockquote>')
562 self.body.append('</informalfigure>\n')
563
564
565
566 def visit_footer(self, node):
567 raise nodes.SkipChildren
568
569 def depart_footer(self, node):
570 pass
571
572 def visit_footnote(self, node):
573 self.footnotes[node['ids'][0]] = []
574 atts = {'id': node['ids'][0]}
575 if isinstance(node[0], nodes.label):
576 atts['label'] = node[0].astext()
577 self.footnotes[node['ids'][0]].append(
578 self.starttag(node, 'footnote', **atts))
579
580
581
582
583
584
585 self._body = self.body
586 self.body = self.footnotes[node['ids'][0]]
587
588 def depart_footnote(self, node):
589
590
591 self.footnotes[node['ids'][0]].append('</footnote>')
592 self.body = self._body
593 self._body = None
594
595 def visit_footnote_reference(self, node):
596 if node.has_key('refid'):
597 refid = node['refid']
598 else:
599 refid = self.document.nameids[node['refname']]
600
601
602
603
604
605
606
607
608 refs = self.footnote_map.get(refid, [])
609 refs.append((node['ids'][0], self.body, len(self.body),))
610 self.footnote_map[refid] = refs
611
612
613
614
615 self.body.append('<!-- REPLACE WITH FOOTNOTE -->')
616
617 raise nodes.SkipNode
618
619 def visit_header(self, node):
620 pass
621 def depart_header(self, node):
622 pass
623
624
625 def visit_generated(self, node):
626 pass
627 def depart_generated(self, node):
628 pass
629
630 def visit_hint(self, node):
631 self.body.append(self.starttag(node, 'note'))
632 self.body.append('\n<title>%s</title>\n'
633 % (self.language.labels[node.tagname],))
634
635 def depart_hint(self, node):
636 self.body.append('</note>\n')
637
638 def visit_image(self, node):
639 if isinstance(node.parent, nodes.paragraph):
640 element = 'inlinemediaobject'
641 elif isinstance(node.parent, nodes.reference):
642 element = 'inlinemediaobject'
643 else:
644 element = 'mediaobject'
645 atts = node.attributes.copy()
646 atts['fileref'] = atts['uri']
647 alt = None
648 del atts['uri']
649 if atts.has_key('alt'):
650 alt = atts['alt']
651 del atts['alt']
652 if atts.has_key('height'):
653 atts['depth'] = atts['height']
654 del atts['height']
655 self.body.append('<%s>' % element)
656 self.body.append('<imageobject>')
657 self.body.append(self.emptytag(node, 'imagedata', **atts))
658 self.body.append('</imageobject>')
659 if alt:
660 self.body.append('<textobject><phrase>''%s</phrase></textobject>\n' % alt)
661 self.body.append('</%s>' % element)
662
663 def depart_image(self, node):
664 pass
665
666 def visit_important(self, node):
667 self.body.append(self.starttag(node, 'important'))
668
669 def depart_important(self, node):
670 self.body.append('</important>')
671
672
673
674
675 def visit_interpreted(self, node):
676 self.body.append('<constant>\n')
677
678 def depart_interpreted(self, node):
679 self.body.append('</constant>\n')
680
681 def visit_label(self, node):
682
683
684
685 if isinstance(node.parent, nodes.footnote):
686 raise nodes.SkipNode
687
688 elif isinstance(node.parent, nodes.citation):
689 raise nodes.SkipNode
690
691 def depart_label(self, node):
692 pass
693
694 def visit_legend(self, node):
695
696
697 pass
698
699 def depart_legend(self, node):
700 pass
701
702 def visit_line_block(self, node):
703 self.body.append(self.starttag(node, 'literallayout'))
704
705 def depart_line_block(self, node):
706 self.body.append('</literallayout>\n')
707
708 def visit_list_item(self, node):
709 self.body.append(self.starttag(node, 'listitem'))
710
711 def depart_list_item(self, node):
712 self.body.append('</listitem>\n')
713
714 def visit_literal(self, node):
715 self.body.append('<literal>')
716
717 def depart_literal(self, node):
718 self.body.append('</literal>')
719
720 def visit_literal_block(self, node):
721 self.body.append(self.starttag(node, 'programlisting'))
722
723 def depart_literal_block(self, node):
724 self.body.append('</programlisting>\n')
725
726 def visit_note(self, node):
727 self.body.append(self.starttag(node, 'note'))
728 self.body.append('\n<title>%s</title>\n'
729 % (self.language.labels[node.tagname],))
730
731 def depart_note(self, node):
732 self.body.append('</note>\n')
733
734 def visit_option(self, node):
735 self.body.append(self.starttag(node, 'command'))
736 if self.context[-1]:
737 self.body.append(', ')
738
739 def depart_option(self, node):
740 self.context[-1] += 1
741 self.body.append('</command>')
742
743 def visit_option_argument(self, node):
744 self.body.append(node.get('delimiter', ' '))
745 self.body.append(self.starttag(node, 'replaceable', ''))
746
747 def depart_option_argument(self, node):
748 self.body.append('</replaceable>')
749
750 def visit_option_group(self, node):
751 self.body.append(self.starttag(node, 'entry'))
752 self.context.append(0)
753
754 def depart_option_group(self, node):
755 self.context.pop()
756 self.body.append('</entry>\n')
757
758 def visit_option_list(self, node):
759 self.body.append(self.starttag(node, 'informaltable', frame='all'))
760 self.body.append('<tgroup cols="2">\n')
761 self.body.append('<colspec colname="option_col"/>\n')
762 self.body.append('<colspec colname="description_col"/>\n')
763 self.body.append('<tbody>\n')
764
765 def depart_option_list(self, node):
766 self.body.append('</tbody>')
767 self.body.append('</tgroup>\n')
768 self.body.append('</informaltable>\n')
769
770 def visit_option_list_item(self, node):
771 self.body.append(self.starttag(node, 'row'))
772
773 def depart_option_list_item(self, node):
774 self.body.append('</row>\n')
775
776 def visit_option_string(self, node):
777 pass
778
779 def depart_option_string(self, node):
780 pass
781
782
783 def visit_organization(self, node):
784 raise nodes.SkipNode
785
786 def visit_paragraph(self, node):
787 self.body.append(self.starttag(node, 'para', ''))
788
789 def depart_paragraph(self, node):
790 self.body.append('</para>')
791
792
793 visit_problematic = depart_problematic = lambda self, node: None
794
795 def visit_raw(self, node):
796 if node.has_key('format') and node['format'] == 'docbook':
797 self.body.append(node.astext())
798 raise node.SkipNode
799
800 def visit_reference(self, node):
801 atts = {}
802 if node.has_key('refuri'):
803 atts['url'] = node['refuri']
804 self.context.append('ulink')
805 elif node.has_key('refid'):
806 atts['linkend'] = node['refid']
807 self.context.append('link')
808 elif node.has_key('refname'):
809 atts['linkend'] = self.document.nameids[node['refname']]
810 self.context.append('link')
811
812
813 if isinstance(node.parent, nodes.section):
814 self.body.append('<para>')
815 self.body.append(self.starttag(node, self.context[-1], '', **atts))
816
817 def depart_reference(self, node):
818 self.body.append('</%s>' % (self.context.pop(),))
819
820
821 if isinstance(node.parent, nodes.section):
822 self.body.append('</para>')
823
824
825 def visit_revision(self, node):
826 raise nodes.SkipNode
827
828 def visit_row(self, node):
829 self.entry_level = 0
830 self.body.append(self.starttag(node, 'row'))
831
832 def depart_row(self, node):
833 self.body.append('</row>\n')
834
835 def visit_rubric(self, node):
836 self.body.append(self.starttag(node, 'bridgehead'))
837
838 def depart_rubric(self, node):
839 self.body.append('</bridgehead>')
840
841 def visit_section(self, node):
842 if self.section == 0 and self.doctype == 'book':
843 self.body.append(self.starttag(node, 'chapter'))
844 else:
845 self.body.append(self.starttag(node, 'section'))
846 self.section += 1
847
848 def depart_section(self, node):
849 self.section -= 1
850 if self.section == 0 and self.doctype == 'book':
851 self.body.append('</chapter>\n')
852 else:
853 self.body.append('</section>\n')
854
855 def visit_sidebar(self, node):
856 self.body.append(self.starttag(node, 'sidebar'))
857 if isinstance(node[0], nodes.title):
858 self.body.append('<sidebarinfo>\n')
859 self.body.append('<title>%s</title>\n' % node[0].astext())
860 if isinstance(node[1], nodes.subtitle):
861 self.body.append('<subtitle>%s</subtitle>\n' % node[1].astext())
862 self.body.append('</sidebarinfo>\n')
863
864 def depart_sidebar(self, node):
865 self.body.append('</sidebar>\n')
866
867
868 def visit_status(self, node):
869 raise nodes.SkipNode
870
871 def visit_strong(self, node):
872 self.body.append('<emphasis role="strong">')
873
874 def depart_strong(self, node):
875 self.body.append('</emphasis>')
876
877 def visit_subscript(self, node):
878 self.body.append(self.starttag(node, 'subscript', ''))
879
880 def depart_subscript(self, node):
881 self.body.append('</subscript>')
882
883 def visit_substitution_definition(self, node):
884 raise nodes.SkipNode
885
886 def visit_substitution_reference(self, node):
887 self.unimplemented_visit(node)
888
889 def visit_subtitle(self, node):
890
891
892
893 if isinstance(node.parent, nodes.document):
894 self.subtitle = node.astext()
895 raise nodes.SkipNode
896 else:
897
898
899
900 if isinstance(node.parent, nodes.sidebar):
901 raise nodes.SkipNode
902 self.body.append(self.starttag(node, 'subtitle', ''))
903
904 def depart_subtitle(self, node):
905 if not isinstance(node.parent, nodes.document):
906 self.body.append('</subtitle>\n')
907
908
909
910 def visit_superscript(self, node):
911 self.body.append(self.starttag(node, 'superscript', ''))
912
913 def depart_superscript(self, node):
914 self.body.append('</superscript>')
915
916
917 visit_system_message = depart_system_message = lambda self, node: None
918
919 def visit_table(self, node):
920 self.body.append(
921 self.starttag(node, 'informaltable', frame='all')
922 )
923
924 def depart_table(self, node):
925 self.body.append('</informaltable>\n')
926
927
928 def visit_target(self, node):
929
930
931 handled = 0
932 siblings = node.parent.children
933 for i in range(len(siblings)):
934 if siblings[i] is node:
935 if i+1 < len(siblings):
936 next = siblings[i+1]
937 if isinstance(next,nodes.Text):
938 pass
939 elif not next.attributes.has_key('id'):
940 next['id'] = node['ids'][0]
941 handled = 1
942 if not handled:
943 if not node.parent.attributes.has_key('id'):
944
945 node.parent.attributes['id'] = node['ids'][0]
946 handled = 1
947
948
949
950 def depart_target(self, node):
951 pass
952
953 def visit_tbody(self, node):
954 self.body.append(self.starttag(node, 'tbody'))
955
956 def depart_tbody(self, node):
957 self.body.append('</tbody>\n')
958
959 def visit_term(self, node):
960 self.body.append(self.starttag(node, 'term'))
961 self.body.append('<varname>')
962
963 def depart_term(self, node):
964
965
966 self.body.append('</varname>')
967
968 def visit_tgroup(self, node):
969 self.colnames = []
970 atts = {'cols': node['cols']}
971 self.body.append(self.starttag(node, 'tgroup', **atts))
972
973 def depart_tgroup(self, node):
974 self.body.append('</tgroup>\n')
975
976 def visit_thead(self, node):
977 self.body.append(self.starttag(node, 'thead'))
978
979 def depart_thead(self, node):
980 self.body.append('</thead>\n')
981
982 def visit_tip(self, node):
983 self.body.append(self.starttag(node, 'tip'))
984
985 def depart_tip(self, node):
986 self.body.append('</tip>\n')
987
988 def visit_title(self, node):
989
990
991 if isinstance(node.parent, nodes.document):
992 self.title = node.astext()
993 raise nodes.SkipNode
994 elif isinstance(node.parent, nodes.sidebar):
995
996 raise nodes.SkipNode
997 else:
998 self.body.append(self.starttag(node, 'title', ''))
999
1000 def depart_title(self, node):
1001 if not isinstance(node.parent, nodes.document):
1002 self.body.append('</title>\n')
1003
1004 def visit_title_reference(self, node):
1005 self.body.append('<citetitle>')
1006
1007 def depart_title_reference(self, node):
1008 self.body.append('</citetitle>')
1009
1010 def visit_topic(self, node):
1011
1012 if node.get('class') == 'contents':
1013 raise nodes.SkipChildren
1014 elif node.get('class') == 'abstract':
1015 self.body.append(self.starttag(node, 'abstract'))
1016 self.context.append('abstract')
1017 elif node.get('class') == 'dedication':
1018
1019
1020 if self.doctype == 'book':
1021 self.body.append(self.starttag(node, 'dedication'))
1022 self.context.append('dedication')
1023 else:
1024 self.body.append(self.starttag(node, 'section'))
1025 self.context.append('section')
1026
1027
1028 elif node.get('class','') == '':
1029 self.body.append(self.starttag(node, 'section'))
1030 self.context.append('section')
1031 else:
1032
1033 print 'class:', node.get('class')
1034 print node.__class__.__name__
1035 print node
1036 print `node`
1037 print dir(node)
1038 self.unimplemented_visit(node)
1039
1040 def depart_topic(self, node):
1041 if len(self.context):
1042 self.body.append('</%s>\n' % (self.context.pop(),))
1043
1044 def visit_transition(self, node):
1045 pass
1046 def depart_transition(self, node):
1047 pass
1048
1049
1050 def visit_version(self, node):
1051 raise nodes.SkipNode
1052
1053 def visit_warning(self, node):
1054 self.body.append(self.starttag(node, 'warning'))
1055
1056 def depart_warning(self, node):
1057 self.body.append('</warning>\n')
1058
1059 def unimplemented_visit(self, node):
1060 raise NotImplementedError('visiting unimplemented node type: %s'
1061 % node.__class__.__name__)
1062
1063
1064class SummaryExtractor(NodeVisitor):
1065 """A SummaryExtractor creates a document containing the first sentence of
1066 a source document."""
1067
1068 def __init__(self, document):
1069
1070 NodeVisitor.__init__(self, document)
1071 self.summary = None
1072
1073
1074 def visit_paragraph(self, node):
1075 """Copy the paragraph but only keep the first sentence."""
1076
1077 if self.summary is not None:
1078 return
1079
1080 summary_pieces = []
1081
1082
1083 for child in node:
1084 if isinstance(child, Text):
1085 m = re.match(r'(\s*[\w\W]*?\.)(\s|$)', child.data)
1086 if m:
1087 summary_pieces.append(Text(m.group(1)))
1088 break
1089 else:
1090 summary_pieces.append(Text(child))
1091 else:
1092 summary_pieces.append(child)
1093
1094 self.summary = self.document.copy()
1095 para = node.copy()
1096 para[:] = summary_pieces
1097 self.summary[:] = [para]
1098
1099
1100 def unknown_visit(self, node):
1101 'Ignore all unknown nodes'
1102
1103 pass
1104
1105
1106class RST(Formatter):
1107 """Format summary and detail documentation according to restructured text markup.
1108 """
1109
1110 def format(self, decl):
1111
1112 def ref(name, rawtext, text, lineno, inliner,
1113 options={}, content=[]):
1114
1115 name = utils.unescape(text)
1116 uri = self.lookup_symbol(name, decl.name[:-1])
1117 if uri:
1118 node = reference(rawtext, name, refid=uri, **options)
1119 else:
1120 node = emphasis(rawtext, name)
1121 return [node], []
1122
1123 roles.register_local_role('', ref)
1124
1125 errstream = StringIO.StringIO()
1126 settings = {}
1127 settings['halt_level'] = 2
1128 settings['warning_stream'] = errstream
1129 settings['traceback'] = True
1130
1131 doc = decl.annotations.get('doc')
1132 if doc:
1133 try:
1134 doctree = publish_doctree(doc.text, settings_overrides=settings)
1135
1136 extractor = SummaryExtractor(doctree)
1137 doctree.walk(extractor)
1138
1139 reader = docutils.readers.doctree.Reader(parser_name='null')
1140
1141
1142 if extractor.summary:
1143 pub = Publisher(reader, None, None,
1144 source=io.DocTreeInput(extractor.summary),
1145 destination_class=io.StringOutput)
1146 pub.writer = Writer()
1147 pub.process_programmatic_settings(None, None, None)
1148 dummy = pub.publish(enable_exit_status=None)
1149 summary = pub.writer.output
1150 else:
1151 summary = ''
1152
1153
1154 pub = Publisher(reader, None, None,
1155 source=io.DocTreeInput(doctree),
1156 destination_class=io.StringOutput)
1157 pub.writer = Writer()
1158 pub.process_programmatic_settings(None, None, None)
1159 dummy = pub.publish(enable_exit_status=None)
1160 details = pub.writer.output
1161
1162 return Struct(summary, details)
1163
1164 except docutils.utils.SystemMessage, error:
1165 xx, line, message = str(error).split(':', 2)
1166 print 'In DocString attached to declaration at %s:%d:'%(decl.file.name,
1167 decl.line)
1168 print ' line %s:%s'%(line, message)
1169
1170 return Struct('', '')
1171
Generated on Thu Apr 16 16:27:16 2009 by
synopsis (version devel)