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