8 Derived from Sphinx's plain-text sphinx builder.
10 :copyright: Copyright 2007-2009 by the Sphinx team, see Sphinx's AUTHORS.
11 Copyright 2009 by Kouhei Sutou.
12 :license: BSD, see LICENSE for details.
19 from docutils
import nodes, writers
20 from docutils.io
import StringOutput
22 from sphinx.util
import ensuredir, os_path
23 from sphinx.builders
import Builder
27 settings_spec = (
'No options here.',
'', ())
28 settings_defaults = {}
33 writers.Writer.__init__(self)
38 self.document.walkabout(visitor)
45 sectionchars =
'*=-~"+'
48 nodes.NodeVisitor.__init__(self, document)
58 self.states.append([])
59 self.stateindent.append(indent)
60 def end_state(self, wrap=True, end=[''], first=None):
61 content = self.states.pop()
63 indent = self.stateindent.pop()
70 res = textwrap.wrap(
''.join(toformat), width=MAXWIDTH-maxindent)
72 res =
''.join(toformat).splitlines()
75 result.append((indent, res))
76 for itemindent, item
in content:
81 result.append((indent + itemindent, item))
84 if first
is not None and result:
85 itemindent, item = result[0]
87 result.insert(0, (itemindent - indent, [first + item[0]]))
88 result[1] = (itemindent, item[1:])
89 self.
states[-1].extend(result)
95 self.
body =
'\n'.join(line
and (
' '*indent + line)
96 for indent, lines
in self.
states[0]
114 visit_sidebar = visit_topic
115 depart_sidebar = depart_topic
135 if isinstance(node.parent, nodes.Admonition):
136 self.add_text(node.astext()+
': ')
140 text =
''.join(x[1]
for x
in self.states.pop()
if x[0] == -1)
142 self.stateindent.pop()
156 if node.has_key(
'platform'):
158 self.add_text(
_(
'Platform: %s') % node[
'platform'])
169 if node.parent[
'desctype']
in (
'class',
'exception'):
170 self.add_text(
'%s ' % node.parent[
'desctype'])
191 self.add_text(
' -> ')
243 for production
in node:
244 names.append(production[
'tokenname'])
245 maxlen = max(len(name)
for name
in names)
246 for production
in node:
247 if production[
'tokenname']:
248 self.add_text(production[
'tokenname'].ljust(maxlen) +
' ::=')
249 lastname = production[
'tokenname']
251 self.add_text(
'%s ' % (
' '*len(lastname)))
252 self.add_text(production.astext() +
'\n')
253 self.end_state(wrap=
False)
262 self.
_footnote = node.children[0].astext().strip()
268 if len(node)
and isinstance(node[0], nodes.label):
310 self.add_text(node[
'delimiter'])
337 self.table.append(
'sep')
342 self.table.append([])
347 if node.has_key(
'morerows')
or node.has_key(
'morecols'):
348 raise NotImplementedError(
'Column or row spanning cells are '
352 text =
'\n'.join(
'\n'.join(x[1])
for x
in self.states.pop())
353 self.stateindent.pop()
358 raise NotImplementedError(
'Nested tables are not supported.')
362 lines = self.
table[1:]
364 colwidths = self.
table[0]
365 realwidths = colwidths[:]
370 separator = len(fmted_rows)
373 for i, cell
in enumerate(line):
374 par = textwrap.wrap(cell, width=colwidths[i])
376 maxwidth = max(map(len, par))
379 realwidths[i] = max(realwidths[i], maxwidth)
381 fmted_rows.append(cells)
383 def writesep(char='-'):
385 for width
in realwidths:
386 out.append(char * (width+2))
391 lines = map(
None, *row)
394 for i, cell
in enumerate(line):
396 out.append(
' ' + cell.ljust(realwidths[i]+1))
398 out.append(
' ' * (realwidths[i] + 2))
402 for i, row
in enumerate(fmted_rows):
403 if separator
and i == separator:
414 self.
add_text(
', '.join(n.astext()
for n
in node.children[0].children)
426 self.
add_text(
'=' * (MAXWIDTH - indent))
436 self._list_counter = 0
441 self._list_counter = -2
446 if self._list_counter == -1:
449 elif self._list_counter == -2:
454 self._list_counter += 1
455 self.new_state(len(str(self._list_counter)) + 2)
466 isinstance(node[1], nodes.classifier)
528 def _visit_admonition(self, node):
530 def _make_depart_admonition(name):
532 self.
end_state(first=admonitionlabels[name] +
': ')
533 return depart_admonition
535 visit_attention = _visit_admonition
536 depart_attention = _make_depart_admonition(
'attention')
537 visit_caution = _visit_admonition
538 depart_caution = _make_depart_admonition(
'caution')
539 visit_danger = _visit_admonition
540 depart_danger = _make_depart_admonition(
'danger')
541 visit_error = _visit_admonition
542 depart_error = _make_depart_admonition(
'error')
543 visit_hint = _visit_admonition
544 depart_hint = _make_depart_admonition(
'hint')
545 visit_important = _visit_admonition
546 depart_important = _make_depart_admonition(
'important')
547 visit_note = _visit_admonition
548 depart_note = _make_depart_admonition(
'note')
549 visit_tip = _visit_admonition
550 depart_tip = _make_depart_admonition(
'tip')
551 visit_warning = _visit_admonition
552 depart_warning = _make_depart_admonition(
'warning')
557 self.
add_text(versionlabels[node[
'type']] % node[
'version'] +
': ')
559 self.
add_text(versionlabels[node[
'type']] % node[
'version'] +
'.')
594 if not isinstance(node.parent, nodes.Admonition)
or \
595 isinstance(node.parent, addnodes.seealso):
598 if not isinstance(node.parent, nodes.Admonition)
or \
599 isinstance(node.parent, addnodes.seealso):
644 if node.hasattr(
'explanation'):
645 self.
add_text(
' (%s)' % node[
'explanation'])
668 self.add_text(
'[%s]' % node.astext())
672 self.
add_text(
'[%s]' % node.astext())
697 self.
add_text(
'<SYSTEM MESSAGE: %s>' % node.astext())
709 raise NotImplementedError(
'Unknown node: ' + node.__class__.__name__)
720 for docname
in self.env.found_docs:
721 if docname
not in self.env.all_docs:
724 targetname = self.env.doc2path(docname, self.outdir,
727 targetmtime = path.getmtime(targetname)
731 srcmtime = path.getmtime(self.env.doc2path(docname))
732 if srcmtime > targetmtime:
734 except EnvironmentError:
745 destination = StringOutput(encoding=
'utf-8')
746 self.writer.write(doctree, destination)
747 outfilename = path.join(self.outdir, os_path(docname) + self.
out_suffix)
748 ensuredir(path.dirname(outfilename))
750 f = codecs.open(outfilename,
'w',
'utf-8')
752 f.write(self.writer.output)
755 except (IOError, OSError), err:
756 self.warn(
"error writing file %s: %s" % (outfilename, err))
762 app.add_builder(RDocBuilder)