##// END OF EJS Templates
py3: make raise statement python3 compatible...
Pulkit Goyal -
r29158:7c0297bf default
parent child Browse files
Show More
@@ -1,1115 +1,1115 b''
1 1 # -*- coding: utf-8 -*-
2 2 # $Id: manpage.py 6110 2009-08-31 14:40:33Z grubert $
3 3 # Author: Engelbert Gruber <grubert@users.sourceforge.net>
4 4 # Copyright: This module is put into the public domain.
5 5
6 6 """
7 7 Simple man page writer for reStructuredText.
8 8
9 9 Man pages (short for "manual pages") contain system documentation on unix-like
10 10 systems. The pages are grouped in numbered sections:
11 11
12 12 1 executable programs and shell commands
13 13 2 system calls
14 14 3 library functions
15 15 4 special files
16 16 5 file formats
17 17 6 games
18 18 7 miscellaneous
19 19 8 system administration
20 20
21 21 Man pages are written in *troff*, a text file formatting system.
22 22
23 23 See http://www.tldp.org/HOWTO/Man-Page for a start.
24 24
25 25 Man pages have no subsections only parts.
26 26 Standard parts
27 27
28 28 NAME ,
29 29 SYNOPSIS ,
30 30 DESCRIPTION ,
31 31 OPTIONS ,
32 32 FILES ,
33 33 SEE ALSO ,
34 34 BUGS ,
35 35
36 36 and
37 37
38 38 AUTHOR .
39 39
40 40 A unix-like system keeps an index of the DESCRIPTIONs, which is accesable
41 41 by the command whatis or apropos.
42 42
43 43 """
44 44 from __future__ import absolute_import
45 45
46 46 __docformat__ = 'reStructuredText'
47 47
48 48 import inspect
49 49 import re
50 50
51 51 from docutils import (
52 52 languages,
53 53 nodes,
54 54 writers,
55 55 )
56 56 try:
57 57 import roman
58 58 except ImportError:
59 59 from docutils.utils import roman
60 60 import inspect
61 61
62 62 FIELD_LIST_INDENT = 7
63 63 DEFINITION_LIST_INDENT = 7
64 64 OPTION_LIST_INDENT = 7
65 65 BLOCKQOUTE_INDENT = 3.5
66 66
67 67 # Define two macros so man/roff can calculate the
68 68 # indent/unindent margins by itself
69 69 MACRO_DEF = (r""".
70 70 .nr rst2man-indent-level 0
71 71 .
72 72 .de1 rstReportMargin
73 73 \\$1 \\n[an-margin]
74 74 level \\n[rst2man-indent-level]
75 75 level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
76 76 -
77 77 \\n[rst2man-indent0]
78 78 \\n[rst2man-indent1]
79 79 \\n[rst2man-indent2]
80 80 ..
81 81 .de1 INDENT
82 82 .\" .rstReportMargin pre:
83 83 . RS \\$1
84 84 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
85 85 . nr rst2man-indent-level +1
86 86 .\" .rstReportMargin post:
87 87 ..
88 88 .de UNINDENT
89 89 . RE
90 90 .\" indent \\n[an-margin]
91 91 .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
92 92 .nr rst2man-indent-level -1
93 93 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
94 94 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
95 95 ..
96 96 """)
97 97
98 98 class Writer(writers.Writer):
99 99
100 100 supported = ('manpage')
101 101 """Formats this writer supports."""
102 102
103 103 output = None
104 104 """Final translated form of `document`."""
105 105
106 106 def __init__(self):
107 107 writers.Writer.__init__(self)
108 108 self.translator_class = Translator
109 109
110 110 def translate(self):
111 111 visitor = self.translator_class(self.document)
112 112 self.document.walkabout(visitor)
113 113 self.output = visitor.astext()
114 114
115 115
116 116 class Table(object):
117 117 def __init__(self):
118 118 self._rows = []
119 119 self._options = ['center']
120 120 self._tab_char = '\t'
121 121 self._coldefs = []
122 122 def new_row(self):
123 123 self._rows.append([])
124 124 def append_separator(self, separator):
125 125 """Append the separator for table head."""
126 126 self._rows.append([separator])
127 127 def append_cell(self, cell_lines):
128 128 """cell_lines is an array of lines"""
129 129 start = 0
130 130 if len(cell_lines) > 0 and cell_lines[0] == '.sp\n':
131 131 start = 1
132 132 self._rows[-1].append(cell_lines[start:])
133 133 if len(self._coldefs) < len(self._rows[-1]):
134 134 self._coldefs.append('l')
135 135 def _minimize_cell(self, cell_lines):
136 136 """Remove leading and trailing blank and ``.sp`` lines"""
137 137 while (cell_lines and cell_lines[0] in ('\n', '.sp\n')):
138 138 del cell_lines[0]
139 139 while (cell_lines and cell_lines[-1] in ('\n', '.sp\n')):
140 140 del cell_lines[-1]
141 141 def as_list(self):
142 142 text = ['.TS\n']
143 143 text.append(' '.join(self._options) + ';\n')
144 144 text.append('|%s|.\n' % ('|'.join(self._coldefs)))
145 145 for row in self._rows:
146 146 # row = array of cells. cell = array of lines.
147 147 text.append('_\n') # line above
148 148 text.append('T{\n')
149 149 for i in range(len(row)):
150 150 cell = row[i]
151 151 self._minimize_cell(cell)
152 152 text.extend(cell)
153 153 if not text[-1].endswith('\n'):
154 154 text[-1] += '\n'
155 155 if i < len(row) - 1:
156 156 text.append('T}'+self._tab_char+'T{\n')
157 157 else:
158 158 text.append('T}\n')
159 159 text.append('_\n')
160 160 text.append('.TE\n')
161 161 return text
162 162
163 163 class Translator(nodes.NodeVisitor):
164 164 """"""
165 165
166 166 words_and_spaces = re.compile(r'\S+| +|\n')
167 167 document_start = """Man page generated from reStructuredText."""
168 168
169 169 def __init__(self, document):
170 170 nodes.NodeVisitor.__init__(self, document)
171 171 self.settings = settings = document.settings
172 172 lcode = settings.language_code
173 173 arglen = len(inspect.getargspec(languages.get_language)[0])
174 174 if arglen == 2:
175 175 self.language = languages.get_language(lcode,
176 176 self.document.reporter)
177 177 else:
178 178 self.language = languages.get_language(lcode)
179 179 self.head = []
180 180 self.body = []
181 181 self.foot = []
182 182 self.section_level = 0
183 183 self.context = []
184 184 self.topic_class = ''
185 185 self.colspecs = []
186 186 self.compact_p = 1
187 187 self.compact_simple = None
188 188 # the list style "*" bullet or "#" numbered
189 189 self._list_char = []
190 190 # writing the header .TH and .SH NAME is postboned after
191 191 # docinfo.
192 192 self._docinfo = {
193 193 "title" : "", "title_upper": "",
194 194 "subtitle" : "",
195 195 "manual_section" : "", "manual_group" : "",
196 196 "author" : [],
197 197 "date" : "",
198 198 "copyright" : "",
199 199 "version" : "",
200 200 }
201 201 self._docinfo_keys = [] # a list to keep the sequence as in source.
202 202 self._docinfo_names = {} # to get name from text not normalized.
203 203 self._in_docinfo = None
204 204 self._active_table = None
205 205 self._in_literal = False
206 206 self.header_written = 0
207 207 self._line_block = 0
208 208 self.authors = []
209 209 self.section_level = 0
210 210 self._indent = [0]
211 211 # central definition of simple processing rules
212 212 # what to output on : visit, depart
213 213 # Do not use paragraph requests ``.PP`` because these set indentation.
214 214 # use ``.sp``. Remove superfluous ``.sp`` in ``astext``.
215 215 #
216 216 # Fonts are put on a stack, the top one is used.
217 217 # ``.ft P`` or ``\\fP`` pop from stack.
218 218 # ``B`` bold, ``I`` italic, ``R`` roman should be available.
219 219 # Hopefully ``C`` courier too.
220 220 self.defs = {
221 221 'indent' : ('.INDENT %.1f\n', '.UNINDENT\n'),
222 222 'definition_list_item' : ('.TP', ''),
223 223 'field_name' : ('.TP\n.B ', '\n'),
224 224 'literal' : ('\\fB', '\\fP'),
225 225 'literal_block' : ('.sp\n.nf\n.ft C\n', '\n.ft P\n.fi\n'),
226 226
227 227 'option_list_item' : ('.TP\n', ''),
228 228
229 229 'reference' : (r'\%', r'\:'),
230 230 'emphasis': ('\\fI', '\\fP'),
231 231 'strong' : ('\\fB', '\\fP'),
232 232 'term' : ('\n.B ', '\n'),
233 233 'title_reference' : ('\\fI', '\\fP'),
234 234
235 235 'topic-title' : ('.SS ',),
236 236 'sidebar-title' : ('.SS ',),
237 237
238 238 'problematic' : ('\n.nf\n', '\n.fi\n'),
239 239 }
240 240 # NOTE don't specify the newline before a dot-command, but ensure
241 241 # it is there.
242 242
243 243 def comment_begin(self, text):
244 244 """Return commented version of the passed text WITHOUT end of
245 245 line/comment."""
246 246 prefix = '.\\" '
247 247 out_text = ''.join(
248 248 [(prefix + in_line + '\n')
249 249 for in_line in text.split('\n')])
250 250 return out_text
251 251
252 252 def comment(self, text):
253 253 """Return commented version of the passed text."""
254 254 return self.comment_begin(text)+'.\n'
255 255
256 256 def ensure_eol(self):
257 257 """Ensure the last line in body is terminated by new line."""
258 258 if self.body[-1][-1] != '\n':
259 259 self.body.append('\n')
260 260
261 261 def astext(self):
262 262 """Return the final formatted document as a string."""
263 263 if not self.header_written:
264 264 # ensure we get a ".TH" as viewers require it.
265 265 self.head.append(self.header())
266 266 # filter body
267 267 for i in xrange(len(self.body) - 1, 0, -1):
268 268 # remove superfluous vertical gaps.
269 269 if self.body[i] == '.sp\n':
270 270 if self.body[i - 1][:4] in ('.BI ','.IP '):
271 271 self.body[i] = '.\n'
272 272 elif (self.body[i - 1][:3] == '.B ' and
273 273 self.body[i - 2][:4] == '.TP\n'):
274 274 self.body[i] = '.\n'
275 275 elif (self.body[i - 1] == '\n' and
276 276 self.body[i - 2][0] != '.' and
277 277 (self.body[i - 3][:7] == '.TP\n.B '
278 278 or self.body[i - 3][:4] == '\n.B ')
279 279 ):
280 280 self.body[i] = '.\n'
281 281 return ''.join(self.head + self.body + self.foot)
282 282
283 283 def deunicode(self, text):
284 284 text = text.replace(u'\xa0', '\\ ')
285 285 text = text.replace(u'\u2020', '\\(dg')
286 286 return text
287 287
288 288 def visit_Text(self, node):
289 289 text = node.astext()
290 290 text = text.replace('\\','\\e')
291 291 replace_pairs = [
292 292 (u'-', ur'\-'),
293 293 (u'\'', ur'\(aq'),
294 294 (u'Β΄', ur'\''),
295 295 (u'`', ur'\(ga'),
296 296 ]
297 297 for (in_char, out_markup) in replace_pairs:
298 298 text = text.replace(in_char, out_markup)
299 299 # unicode
300 300 text = self.deunicode(text)
301 301 if self._in_literal:
302 302 # prevent interpretation of "." at line start
303 303 if text[0] == '.':
304 304 text = '\\&' + text
305 305 text = text.replace('\n.', '\n\\&.')
306 306 self.body.append(text)
307 307
308 308 def depart_Text(self, node):
309 309 pass
310 310
311 311 def list_start(self, node):
312 312 class enum_char(object):
313 313 enum_style = {
314 314 'bullet' : '\\(bu',
315 315 'emdash' : '\\(em',
316 316 }
317 317
318 318 def __init__(self, style):
319 319 self._style = style
320 320 if 'start' in node:
321 321 self._cnt = node['start'] - 1
322 322 else:
323 323 self._cnt = 0
324 324 self._indent = 2
325 325 if style == 'arabic':
326 326 # indentation depends on number of children
327 327 # and start value.
328 328 self._indent = len(str(len(node.children)))
329 329 self._indent += len(str(self._cnt)) + 1
330 330 elif style == 'loweralpha':
331 331 self._cnt += ord('a') - 1
332 332 self._indent = 3
333 333 elif style == 'upperalpha':
334 334 self._cnt += ord('A') - 1
335 335 self._indent = 3
336 336 elif style.endswith('roman'):
337 337 self._indent = 5
338 338
339 339 def next(self):
340 340 if self._style == 'bullet':
341 341 return self.enum_style[self._style]
342 342 elif self._style == 'emdash':
343 343 return self.enum_style[self._style]
344 344 self._cnt += 1
345 345 # TODO add prefix postfix
346 346 if self._style == 'arabic':
347 347 return "%d." % self._cnt
348 348 elif self._style in ('loweralpha', 'upperalpha'):
349 349 return "%c." % self._cnt
350 350 elif self._style.endswith('roman'):
351 351 res = roman.toRoman(self._cnt) + '.'
352 352 if self._style.startswith('upper'):
353 353 return res.upper()
354 354 return res.lower()
355 355 else:
356 356 return "%d." % self._cnt
357 357 def get_width(self):
358 358 return self._indent
359 359 def __repr__(self):
360 360 return 'enum_style-%s' % list(self._style)
361 361
362 362 if 'enumtype' in node:
363 363 self._list_char.append(enum_char(node['enumtype']))
364 364 else:
365 365 self._list_char.append(enum_char('bullet'))
366 366 if len(self._list_char) > 1:
367 367 # indent nested lists
368 368 self.indent(self._list_char[-2].get_width())
369 369 else:
370 370 self.indent(self._list_char[-1].get_width())
371 371
372 372 def list_end(self):
373 373 self.dedent()
374 374 self._list_char.pop()
375 375
376 376 def header(self):
377 377 tmpl = (".TH %(title_upper)s %(manual_section)s"
378 378 " \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n"
379 379 ".SH NAME\n"
380 380 "%(title)s \- %(subtitle)s\n")
381 381 return tmpl % self._docinfo
382 382
383 383 def append_header(self):
384 384 """append header with .TH and .SH NAME"""
385 385 # NOTE before everything
386 386 # .TH title_upper section date source manual
387 387 if self.header_written:
388 388 return
389 389 self.body.append(self.header())
390 390 self.body.append(MACRO_DEF)
391 391 self.header_written = 1
392 392
393 393 def visit_address(self, node):
394 394 self.visit_docinfo_item(node, 'address')
395 395
396 396 def depart_address(self, node):
397 397 pass
398 398
399 399 def visit_admonition(self, node, name=None):
400 400 if name:
401 401 self.body.append('.IP %s\n' %
402 402 self.language.labels.get(name, name))
403 403
404 404 def depart_admonition(self, node):
405 405 self.body.append('.RE\n')
406 406
407 407 def visit_attention(self, node):
408 408 self.visit_admonition(node, 'attention')
409 409
410 410 depart_attention = depart_admonition
411 411
412 412 def visit_docinfo_item(self, node, name):
413 413 if name == 'author':
414 414 self._docinfo[name].append(node.astext())
415 415 else:
416 416 self._docinfo[name] = node.astext()
417 417 self._docinfo_keys.append(name)
418 raise nodes.SkipNode
418 raise nodes.SkipNode()
419 419
420 420 def depart_docinfo_item(self, node):
421 421 pass
422 422
423 423 def visit_author(self, node):
424 424 self.visit_docinfo_item(node, 'author')
425 425
426 426 depart_author = depart_docinfo_item
427 427
428 428 def visit_authors(self, node):
429 429 # _author is called anyway.
430 430 pass
431 431
432 432 def depart_authors(self, node):
433 433 pass
434 434
435 435 def visit_block_quote(self, node):
436 436 # BUG/HACK: indent always uses the _last_ indentation,
437 437 # thus we need two of them.
438 438 self.indent(BLOCKQOUTE_INDENT)
439 439 self.indent(0)
440 440
441 441 def depart_block_quote(self, node):
442 442 self.dedent()
443 443 self.dedent()
444 444
445 445 def visit_bullet_list(self, node):
446 446 self.list_start(node)
447 447
448 448 def depart_bullet_list(self, node):
449 449 self.list_end()
450 450
451 451 def visit_caption(self, node):
452 452 pass
453 453
454 454 def depart_caption(self, node):
455 455 pass
456 456
457 457 def visit_caution(self, node):
458 458 self.visit_admonition(node, 'caution')
459 459
460 460 depart_caution = depart_admonition
461 461
462 462 def visit_citation(self, node):
463 463 num, text = node.astext().split(None, 1)
464 464 num = num.strip()
465 465 self.body.append('.IP [%s] 5\n' % num)
466 466
467 467 def depart_citation(self, node):
468 468 pass
469 469
470 470 def visit_citation_reference(self, node):
471 471 self.body.append('['+node.astext()+']')
472 raise nodes.SkipNode
472 raise nodes.SkipNode()
473 473
474 474 def visit_classifier(self, node):
475 475 pass
476 476
477 477 def depart_classifier(self, node):
478 478 pass
479 479
480 480 def visit_colspec(self, node):
481 481 self.colspecs.append(node)
482 482
483 483 def depart_colspec(self, node):
484 484 pass
485 485
486 486 def write_colspecs(self):
487 487 self.body.append("%s.\n" % ('L '*len(self.colspecs)))
488 488
489 489 def visit_comment(self, node,
490 490 sub=re.compile('-(?=-)').sub):
491 491 self.body.append(self.comment(node.astext()))
492 raise nodes.SkipNode
492 raise nodes.SkipNode()
493 493
494 494 def visit_contact(self, node):
495 495 self.visit_docinfo_item(node, 'contact')
496 496
497 497 depart_contact = depart_docinfo_item
498 498
499 499 def visit_container(self, node):
500 500 pass
501 501
502 502 def depart_container(self, node):
503 503 pass
504 504
505 505 def visit_compound(self, node):
506 506 pass
507 507
508 508 def depart_compound(self, node):
509 509 pass
510 510
511 511 def visit_copyright(self, node):
512 512 self.visit_docinfo_item(node, 'copyright')
513 513
514 514 def visit_danger(self, node):
515 515 self.visit_admonition(node, 'danger')
516 516
517 517 depart_danger = depart_admonition
518 518
519 519 def visit_date(self, node):
520 520 self.visit_docinfo_item(node, 'date')
521 521
522 522 def visit_decoration(self, node):
523 523 pass
524 524
525 525 def depart_decoration(self, node):
526 526 pass
527 527
528 528 def visit_definition(self, node):
529 529 pass
530 530
531 531 def depart_definition(self, node):
532 532 pass
533 533
534 534 def visit_definition_list(self, node):
535 535 self.indent(DEFINITION_LIST_INDENT)
536 536
537 537 def depart_definition_list(self, node):
538 538 self.dedent()
539 539
540 540 def visit_definition_list_item(self, node):
541 541 self.body.append(self.defs['definition_list_item'][0])
542 542
543 543 def depart_definition_list_item(self, node):
544 544 self.body.append(self.defs['definition_list_item'][1])
545 545
546 546 def visit_description(self, node):
547 547 pass
548 548
549 549 def depart_description(self, node):
550 550 pass
551 551
552 552 def visit_docinfo(self, node):
553 553 self._in_docinfo = 1
554 554
555 555 def depart_docinfo(self, node):
556 556 self._in_docinfo = None
557 557 # NOTE nothing should be written before this
558 558 self.append_header()
559 559
560 560 def visit_doctest_block(self, node):
561 561 self.body.append(self.defs['literal_block'][0])
562 562 self._in_literal = True
563 563
564 564 def depart_doctest_block(self, node):
565 565 self._in_literal = False
566 566 self.body.append(self.defs['literal_block'][1])
567 567
568 568 def visit_document(self, node):
569 569 # no blank line between comment and header.
570 570 self.body.append(self.comment(self.document_start).rstrip()+'\n')
571 571 # writing header is postboned
572 572 self.header_written = 0
573 573
574 574 def depart_document(self, node):
575 575 if self._docinfo['author']:
576 576 self.body.append('.SH AUTHOR\n%s\n'
577 577 % ', '.join(self._docinfo['author']))
578 578 skip = ('author', 'copyright', 'date',
579 579 'manual_group', 'manual_section',
580 580 'subtitle',
581 581 'title', 'title_upper', 'version')
582 582 for name in self._docinfo_keys:
583 583 if name == 'address':
584 584 self.body.append("\n%s:\n%s%s.nf\n%s\n.fi\n%s%s" % (
585 585 self.language.labels.get(name, name),
586 586 self.defs['indent'][0] % 0,
587 587 self.defs['indent'][0] % BLOCKQOUTE_INDENT,
588 588 self._docinfo[name],
589 589 self.defs['indent'][1],
590 590 self.defs['indent'][1]))
591 591 elif name not in skip:
592 592 if name in self._docinfo_names:
593 593 label = self._docinfo_names[name]
594 594 else:
595 595 label = self.language.labels.get(name, name)
596 596 self.body.append("\n%s: %s\n" % (label, self._docinfo[name]))
597 597 if self._docinfo['copyright']:
598 598 self.body.append('.SH COPYRIGHT\n%s\n'
599 599 % self._docinfo['copyright'])
600 600 self.body.append(self.comment(
601 601 'Generated by docutils manpage writer.\n'))
602 602
603 603 def visit_emphasis(self, node):
604 604 self.body.append(self.defs['emphasis'][0])
605 605
606 606 def depart_emphasis(self, node):
607 607 self.body.append(self.defs['emphasis'][1])
608 608
609 609 def visit_entry(self, node):
610 610 # a cell in a table row
611 611 if 'morerows' in node:
612 612 self.document.reporter.warning('"table row spanning" not supported',
613 613 base_node=node)
614 614 if 'morecols' in node:
615 615 self.document.reporter.warning(
616 616 '"table cell spanning" not supported', base_node=node)
617 617 self.context.append(len(self.body))
618 618
619 619 def depart_entry(self, node):
620 620 start = self.context.pop()
621 621 self._active_table.append_cell(self.body[start:])
622 622 del self.body[start:]
623 623
624 624 def visit_enumerated_list(self, node):
625 625 self.list_start(node)
626 626
627 627 def depart_enumerated_list(self, node):
628 628 self.list_end()
629 629
630 630 def visit_error(self, node):
631 631 self.visit_admonition(node, 'error')
632 632
633 633 depart_error = depart_admonition
634 634
635 635 def visit_field(self, node):
636 636 pass
637 637
638 638 def depart_field(self, node):
639 639 pass
640 640
641 641 def visit_field_body(self, node):
642 642 if self._in_docinfo:
643 643 name_normalized = self._field_name.lower().replace(" ","_")
644 644 self._docinfo_names[name_normalized] = self._field_name
645 645 self.visit_docinfo_item(node, name_normalized)
646 raise nodes.SkipNode
646 raise nodes.SkipNode()
647 647
648 648 def depart_field_body(self, node):
649 649 pass
650 650
651 651 def visit_field_list(self, node):
652 652 self.indent(FIELD_LIST_INDENT)
653 653
654 654 def depart_field_list(self, node):
655 655 self.dedent()
656 656
657 657 def visit_field_name(self, node):
658 658 if self._in_docinfo:
659 659 self._field_name = node.astext()
660 raise nodes.SkipNode
660 raise nodes.SkipNode()
661 661 else:
662 662 self.body.append(self.defs['field_name'][0])
663 663
664 664 def depart_field_name(self, node):
665 665 self.body.append(self.defs['field_name'][1])
666 666
667 667 def visit_figure(self, node):
668 668 self.indent(2.5)
669 669 self.indent(0)
670 670
671 671 def depart_figure(self, node):
672 672 self.dedent()
673 673 self.dedent()
674 674
675 675 def visit_footer(self, node):
676 676 self.document.reporter.warning('"footer" not supported',
677 677 base_node=node)
678 678
679 679 def depart_footer(self, node):
680 680 pass
681 681
682 682 def visit_footnote(self, node):
683 683 num, text = node.astext().split(None, 1)
684 684 num = num.strip()
685 685 self.body.append('.IP [%s] 5\n' % self.deunicode(num))
686 686
687 687 def depart_footnote(self, node):
688 688 pass
689 689
690 690 def footnote_backrefs(self, node):
691 691 self.document.reporter.warning('"footnote_backrefs" not supported',
692 692 base_node=node)
693 693
694 694 def visit_footnote_reference(self, node):
695 695 self.body.append('['+self.deunicode(node.astext())+']')
696 raise nodes.SkipNode
696 raise nodes.SkipNode()
697 697
698 698 def depart_footnote_reference(self, node):
699 699 pass
700 700
701 701 def visit_generated(self, node):
702 702 pass
703 703
704 704 def depart_generated(self, node):
705 705 pass
706 706
707 707 def visit_header(self, node):
708 raise NotImplementedError, node.astext()
708 raise NotImplementedError(node.astext())
709 709
710 710 def depart_header(self, node):
711 711 pass
712 712
713 713 def visit_hint(self, node):
714 714 self.visit_admonition(node, 'hint')
715 715
716 716 depart_hint = depart_admonition
717 717
718 718 def visit_subscript(self, node):
719 719 self.body.append('\\s-2\\d')
720 720
721 721 def depart_subscript(self, node):
722 722 self.body.append('\\u\\s0')
723 723
724 724 def visit_superscript(self, node):
725 725 self.body.append('\\s-2\\u')
726 726
727 727 def depart_superscript(self, node):
728 728 self.body.append('\\d\\s0')
729 729
730 730 def visit_attribution(self, node):
731 731 self.body.append('\\(em ')
732 732
733 733 def depart_attribution(self, node):
734 734 self.body.append('\n')
735 735
736 736 def visit_image(self, node):
737 737 self.document.reporter.warning('"image" not supported',
738 738 base_node=node)
739 739 text = []
740 740 if 'alt' in node.attributes:
741 741 text.append(node.attributes['alt'])
742 742 if 'uri' in node.attributes:
743 743 text.append(node.attributes['uri'])
744 744 self.body.append('[image: %s]\n' % ('/'.join(text)))
745 raise nodes.SkipNode
745 raise nodes.SkipNode()
746 746
747 747 def visit_important(self, node):
748 748 self.visit_admonition(node, 'important')
749 749
750 750 depart_important = depart_admonition
751 751
752 752 def visit_label(self, node):
753 753 # footnote and citation
754 754 if (isinstance(node.parent, nodes.footnote)
755 755 or isinstance(node.parent, nodes.citation)):
756 raise nodes.SkipNode
756 raise nodes.SkipNode()
757 757 self.document.reporter.warning('"unsupported "label"',
758 758 base_node=node)
759 759 self.body.append('[')
760 760
761 761 def depart_label(self, node):
762 762 self.body.append(']\n')
763 763
764 764 def visit_legend(self, node):
765 765 pass
766 766
767 767 def depart_legend(self, node):
768 768 pass
769 769
770 770 # WHAT should we use .INDENT, .UNINDENT ?
771 771 def visit_line_block(self, node):
772 772 self._line_block += 1
773 773 if self._line_block == 1:
774 774 self.body.append('.sp\n')
775 775 self.body.append('.nf\n')
776 776 else:
777 777 self.body.append('.in +2\n')
778 778
779 779 def depart_line_block(self, node):
780 780 self._line_block -= 1
781 781 if self._line_block == 0:
782 782 self.body.append('.fi\n')
783 783 self.body.append('.sp\n')
784 784 else:
785 785 self.body.append('.in -2\n')
786 786
787 787 def visit_line(self, node):
788 788 pass
789 789
790 790 def depart_line(self, node):
791 791 self.body.append('\n')
792 792
793 793 def visit_list_item(self, node):
794 794 # man 7 man argues to use ".IP" instead of ".TP"
795 795 self.body.append('.IP %s %d\n' % (
796 796 self._list_char[-1].next(),
797 797 self._list_char[-1].get_width(),))
798 798
799 799 def depart_list_item(self, node):
800 800 pass
801 801
802 802 def visit_literal(self, node):
803 803 self.body.append(self.defs['literal'][0])
804 804
805 805 def depart_literal(self, node):
806 806 self.body.append(self.defs['literal'][1])
807 807
808 808 def visit_literal_block(self, node):
809 809 self.body.append(self.defs['literal_block'][0])
810 810 self._in_literal = True
811 811
812 812 def depart_literal_block(self, node):
813 813 self._in_literal = False
814 814 self.body.append(self.defs['literal_block'][1])
815 815
816 816 def visit_meta(self, node):
817 raise NotImplementedError, node.astext()
817 raise NotImplementedError(node.astext())
818 818
819 819 def depart_meta(self, node):
820 820 pass
821 821
822 822 def visit_note(self, node):
823 823 self.visit_admonition(node, 'note')
824 824
825 825 depart_note = depart_admonition
826 826
827 827 def indent(self, by=0.5):
828 828 # if we are in a section ".SH" there already is a .RS
829 829 step = self._indent[-1]
830 830 self._indent.append(by)
831 831 self.body.append(self.defs['indent'][0] % step)
832 832
833 833 def dedent(self):
834 834 self._indent.pop()
835 835 self.body.append(self.defs['indent'][1])
836 836
837 837 def visit_option_list(self, node):
838 838 self.indent(OPTION_LIST_INDENT)
839 839
840 840 def depart_option_list(self, node):
841 841 self.dedent()
842 842
843 843 def visit_option_list_item(self, node):
844 844 # one item of the list
845 845 self.body.append(self.defs['option_list_item'][0])
846 846
847 847 def depart_option_list_item(self, node):
848 848 self.body.append(self.defs['option_list_item'][1])
849 849
850 850 def visit_option_group(self, node):
851 851 # as one option could have several forms it is a group
852 852 # options without parameter bold only, .B, -v
853 853 # options with parameter bold italic, .BI, -f file
854 854 #
855 855 # we do not know if .B or .BI
856 856 self.context.append('.B') # blind guess
857 857 self.context.append(len(self.body)) # to be able to insert later
858 858 self.context.append(0) # option counter
859 859
860 860 def depart_option_group(self, node):
861 861 self.context.pop() # the counter
862 862 start_position = self.context.pop()
863 863 text = self.body[start_position:]
864 864 del self.body[start_position:]
865 865 self.body.append('%s%s\n' % (self.context.pop(), ''.join(text)))
866 866
867 867 def visit_option(self, node):
868 868 # each form of the option will be presented separately
869 869 if self.context[-1] > 0:
870 870 self.body.append(', ')
871 871 if self.context[-3] == '.BI':
872 872 self.body.append('\\')
873 873 self.body.append(' ')
874 874
875 875 def depart_option(self, node):
876 876 self.context[-1] += 1
877 877
878 878 def visit_option_string(self, node):
879 879 # do not know if .B or .BI
880 880 pass
881 881
882 882 def depart_option_string(self, node):
883 883 pass
884 884
885 885 def visit_option_argument(self, node):
886 886 self.context[-3] = '.BI' # bold/italic alternate
887 887 if node['delimiter'] != ' ':
888 888 self.body.append('\\fB%s ' % node['delimiter'])
889 889 elif self.body[len(self.body) - 1].endswith('='):
890 890 # a blank only means no blank in output, just changing font
891 891 self.body.append(' ')
892 892 else:
893 893 # blank backslash blank, switch font then a blank
894 894 self.body.append(' \\ ')
895 895
896 896 def depart_option_argument(self, node):
897 897 pass
898 898
899 899 def visit_organization(self, node):
900 900 self.visit_docinfo_item(node, 'organization')
901 901
902 902 def depart_organization(self, node):
903 903 pass
904 904
905 905 def visit_paragraph(self, node):
906 906 # ``.PP`` : Start standard indented paragraph.
907 907 # ``.LP`` : Start block paragraph, all except the first.
908 908 # ``.P [type]`` : Start paragraph type.
909 909 # NOTE don't use paragraph starts because they reset indentation.
910 910 # ``.sp`` is only vertical space
911 911 self.ensure_eol()
912 912 self.body.append('.sp\n')
913 913
914 914 def depart_paragraph(self, node):
915 915 self.body.append('\n')
916 916
917 917 def visit_problematic(self, node):
918 918 self.body.append(self.defs['problematic'][0])
919 919
920 920 def depart_problematic(self, node):
921 921 self.body.append(self.defs['problematic'][1])
922 922
923 923 def visit_raw(self, node):
924 924 if node.get('format') == 'manpage':
925 925 self.body.append(node.astext() + "\n")
926 926 # Keep non-manpage raw text out of output:
927 raise nodes.SkipNode
927 raise nodes.SkipNode()
928 928
929 929 def visit_reference(self, node):
930 930 """E.g. link or email address."""
931 931 self.body.append(self.defs['reference'][0])
932 932
933 933 def depart_reference(self, node):
934 934 self.body.append(self.defs['reference'][1])
935 935
936 936 def visit_revision(self, node):
937 937 self.visit_docinfo_item(node, 'revision')
938 938
939 939 depart_revision = depart_docinfo_item
940 940
941 941 def visit_row(self, node):
942 942 self._active_table.new_row()
943 943
944 944 def depart_row(self, node):
945 945 pass
946 946
947 947 def visit_section(self, node):
948 948 self.section_level += 1
949 949
950 950 def depart_section(self, node):
951 951 self.section_level -= 1
952 952
953 953 def visit_status(self, node):
954 954 self.visit_docinfo_item(node, 'status')
955 955
956 956 depart_status = depart_docinfo_item
957 957
958 958 def visit_strong(self, node):
959 959 self.body.append(self.defs['strong'][0])
960 960
961 961 def depart_strong(self, node):
962 962 self.body.append(self.defs['strong'][1])
963 963
964 964 def visit_substitution_definition(self, node):
965 965 """Internal only."""
966 raise nodes.SkipNode
966 raise nodes.SkipNode()
967 967
968 968 def visit_substitution_reference(self, node):
969 969 self.document.reporter.warning('"substitution_reference" not supported',
970 970 base_node=node)
971 971
972 972 def visit_subtitle(self, node):
973 973 if isinstance(node.parent, nodes.sidebar):
974 974 self.body.append(self.defs['strong'][0])
975 975 elif isinstance(node.parent, nodes.document):
976 976 self.visit_docinfo_item(node, 'subtitle')
977 977 elif isinstance(node.parent, nodes.section):
978 978 self.body.append(self.defs['strong'][0])
979 979
980 980 def depart_subtitle(self, node):
981 981 # document subtitle calls SkipNode
982 982 self.body.append(self.defs['strong'][1]+'\n.PP\n')
983 983
984 984 def visit_system_message(self, node):
985 985 # TODO add report_level
986 986 #if node['level'] < self.document.reporter['writer'].report_level:
987 987 # Level is too low to display:
988 988 # raise nodes.SkipNode
989 989 attr = {}
990 990 if node.hasattr('id'):
991 991 attr['name'] = node['id']
992 992 if node.hasattr('line'):
993 993 line = ', line %s' % node['line']
994 994 else:
995 995 line = ''
996 996 self.body.append('.IP "System Message: %s/%s (%s:%s)"\n'
997 997 % (node['type'], node['level'], node['source'], line))
998 998
999 999 def depart_system_message(self, node):
1000 1000 pass
1001 1001
1002 1002 def visit_table(self, node):
1003 1003 self._active_table = Table()
1004 1004
1005 1005 def depart_table(self, node):
1006 1006 self.ensure_eol()
1007 1007 self.body.extend(self._active_table.as_list())
1008 1008 self._active_table = None
1009 1009
1010 1010 def visit_target(self, node):
1011 1011 # targets are in-document hyper targets, without any use for man-pages.
1012 raise nodes.SkipNode
1012 raise nodes.SkipNode()
1013 1013
1014 1014 def visit_tbody(self, node):
1015 1015 pass
1016 1016
1017 1017 def depart_tbody(self, node):
1018 1018 pass
1019 1019
1020 1020 def visit_term(self, node):
1021 1021 self.body.append(self.defs['term'][0])
1022 1022
1023 1023 def depart_term(self, node):
1024 1024 self.body.append(self.defs['term'][1])
1025 1025
1026 1026 def visit_tgroup(self, node):
1027 1027 pass
1028 1028
1029 1029 def depart_tgroup(self, node):
1030 1030 pass
1031 1031
1032 1032 def visit_thead(self, node):
1033 1033 # MAYBE double line '='
1034 1034 pass
1035 1035
1036 1036 def depart_thead(self, node):
1037 1037 # MAYBE double line '='
1038 1038 pass
1039 1039
1040 1040 def visit_tip(self, node):
1041 1041 self.visit_admonition(node, 'tip')
1042 1042
1043 1043 depart_tip = depart_admonition
1044 1044
1045 1045 def visit_title(self, node):
1046 1046 if isinstance(node.parent, nodes.topic):
1047 1047 self.body.append(self.defs['topic-title'][0])
1048 1048 elif isinstance(node.parent, nodes.sidebar):
1049 1049 self.body.append(self.defs['sidebar-title'][0])
1050 1050 elif isinstance(node.parent, nodes.admonition):
1051 1051 self.body.append('.IP "')
1052 1052 elif self.section_level == 0:
1053 1053 self._docinfo['title'] = node.astext()
1054 1054 # document title for .TH
1055 1055 self._docinfo['title_upper'] = node.astext().upper()
1056 raise nodes.SkipNode
1056 raise nodes.SkipNode()
1057 1057 elif self.section_level == 1:
1058 1058 self.body.append('.SH ')
1059 1059 for n in node.traverse(nodes.Text):
1060 1060 n.parent.replace(n, nodes.Text(n.astext().upper()))
1061 1061 else:
1062 1062 self.body.append('.SS ')
1063 1063
1064 1064 def depart_title(self, node):
1065 1065 if isinstance(node.parent, nodes.admonition):
1066 1066 self.body.append('"')
1067 1067 self.body.append('\n')
1068 1068
1069 1069 def visit_title_reference(self, node):
1070 1070 """inline citation reference"""
1071 1071 self.body.append(self.defs['title_reference'][0])
1072 1072
1073 1073 def depart_title_reference(self, node):
1074 1074 self.body.append(self.defs['title_reference'][1])
1075 1075
1076 1076 def visit_topic(self, node):
1077 1077 pass
1078 1078
1079 1079 def depart_topic(self, node):
1080 1080 pass
1081 1081
1082 1082 def visit_sidebar(self, node):
1083 1083 pass
1084 1084
1085 1085 def depart_sidebar(self, node):
1086 1086 pass
1087 1087
1088 1088 def visit_rubric(self, node):
1089 1089 pass
1090 1090
1091 1091 def depart_rubric(self, node):
1092 1092 pass
1093 1093
1094 1094 def visit_transition(self, node):
1095 1095 # .PP Begin a new paragraph and reset prevailing indent.
1096 1096 # .sp N leaves N lines of blank space.
1097 1097 # .ce centers the next line
1098 1098 self.body.append('\n.sp\n.ce\n----\n')
1099 1099
1100 1100 def depart_transition(self, node):
1101 1101 self.body.append('\n.ce 0\n.sp\n')
1102 1102
1103 1103 def visit_version(self, node):
1104 1104 self.visit_docinfo_item(node, 'version')
1105 1105
1106 1106 def visit_warning(self, node):
1107 1107 self.visit_admonition(node, 'warning')
1108 1108
1109 1109 depart_warning = depart_admonition
1110 1110
1111 1111 def unimplemented_visit(self, node):
1112 1112 raise NotImplementedError('visiting unimplemented node type: %s'
1113 1113 % node.__class__.__name__)
1114 1114
1115 1115 # vim: set fileencoding=utf-8 et ts=4 ai :
General Comments 0
You need to be logged in to leave comments. Login now