root/galaxy-central/eggs/docutils-0.4-py2.6.egg/docutils/writers/latex2e/__init__.py @ 3

リビジョン 3, 74.8 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1# Author: Engelbert Gruber
2# Contact: grubert@users.sourceforge.net
3# Revision: $Revision: 4242 $
4# Date: $Date: 2006-01-06 00:28:53 +0100 (Fri, 06 Jan 2006) $
5# Copyright: This module has been placed in the public domain.
6
7"""
8LaTeX2e document tree Writer.
9"""
10
11__docformat__ = 'reStructuredText'
12
13# code contributions from several people included, thanks to all.
14# some named: David Abrahams, Julien Letessier, Lele Gaifax, and others.
15#
16# convention deactivate code by two # e.g. ##.
17
18import sys
19import time
20import re
21import string
22from types import ListType
23from docutils import frontend, nodes, languages, writers, utils
24
25
26class Writer(writers.Writer):
27
28    supported = ('latex','latex2e')
29    """Formats this writer supports."""
30
31    settings_spec = (
32        'LaTeX-Specific Options',
33        'The LaTeX "--output-encoding" default is "latin-1:strict".',
34        (('Specify documentclass.  Default is "article".',
35          ['--documentclass'],
36          {'default': 'article', }),
37         ('Specify document options.  Multiple options can be given, '
38          'separated by commas.  Default is "10pt,a4paper".',
39          ['--documentoptions'],
40          {'default': '10pt,a4paper', }),
41         ('Use LaTeX footnotes. LaTeX supports only numbered footnotes (does it?). '
42          'Default: no, uses figures.',
43          ['--use-latex-footnotes'],
44          {'default': 0, 'action': 'store_true',
45           'validator': frontend.validate_boolean}),
46         ('Format for footnote references: one of "superscript" or '
47          '"brackets".  Default is "superscript".',
48          ['--footnote-references'],
49          {'choices': ['superscript', 'brackets'], 'default': 'superscript',
50           'metavar': '<format>',
51           'overrides': 'trim_footnote_reference_space'}),
52         ('Use LaTeX citations. '
53          'Default: no, uses figures which might get mixed with images.',
54          ['--use-latex-citations'],
55          {'default': 0, 'action': 'store_true',
56           'validator': frontend.validate_boolean}),
57         ('Format for block quote attributions: one of "dash" (em-dash '
58          'prefix), "parentheses"/"parens", or "none".  Default is "dash".',
59          ['--attribution'],
60          {'choices': ['dash', 'parentheses', 'parens', 'none'],
61           'default': 'dash', 'metavar': '<format>'}),
62         ('Specify a stylesheet file. The file will be "input" by latex in '
63          'the document header.  Default is no stylesheet ("").  '
64          'Overrides --stylesheet-path.',
65          ['--stylesheet'],
66          {'default': '', 'metavar': '<file>',
67           'overrides': 'stylesheet_path'}),
68         ('Specify a stylesheet file, relative to the current working '
69          'directory.  Overrides --stylesheet.',
70          ['--stylesheet-path'],
71          {'metavar': '<file>', 'overrides': 'stylesheet'}),
72         ('Table of contents by docutils (default) or latex. Latex (writer) '
73          'supports only one ToC per document, but docutils does not write '
74          'pagenumbers.',
75          ['--use-latex-toc'],
76          {'default': 0, 'action': 'store_true',
77           'validator': frontend.validate_boolean}),
78         ('Let LaTeX print author and date, do not show it in docutils '
79          'document info.',
80          ['--use-latex-docinfo'],
81          {'default': 0, 'action': 'store_true',
82           'validator': frontend.validate_boolean}),
83         ('Color of any hyperlinks embedded in text '
84          '(default: "blue", "0" to disable).',
85          ['--hyperlink-color'], {'default': 'blue'}),
86         ('Enable compound enumerators for nested enumerated lists '
87          '(e.g. "1.2.a.ii").  Default: disabled.',
88          ['--compound-enumerators'],
89          {'default': None, 'action': 'store_true',
90           'validator': frontend.validate_boolean}),
91         ('Disable compound enumerators for nested enumerated lists.  This is '
92          'the default.',
93          ['--no-compound-enumerators'],
94          {'action': 'store_false', 'dest': 'compound_enumerators'}),
95         ('Enable section ("." subsection ...) prefixes for compound '
96          'enumerators.  This has no effect without --compound-enumerators.  '
97          'Default: disabled.',
98          ['--section-prefix-for-enumerators'],
99          {'default': None, 'action': 'store_true',
100           'validator': frontend.validate_boolean}),
101         ('Disable section prefixes for compound enumerators.  '
102          'This is the default.',
103          ['--no-section-prefix-for-enumerators'],
104          {'action': 'store_false', 'dest': 'section_prefix_for_enumerators'}),
105         ('Set the separator between section number and enumerator '
106          'for compound enumerated lists.  Default is "-".',
107          ['--section-enumerator-separator'],
108          {'default': '-', 'metavar': '<char>'}),
109         ('When possibile, use verbatim for literal-blocks. '
110          'Default is to always use the mbox environment.',
111          ['--use-verbatim-when-possible'],
112          {'default': 0, 'action': 'store_true',
113           'validator': frontend.validate_boolean}),
114         ('Table style. "standard" with horizontal and vertical lines, '
115          '"booktabs" (LaTeX booktabs style) only horizontal lines '
116          'above and below the table and below the header or "nolines".  '
117          'Default: "standard"',
118          ['--table-style'],
119          {'choices': ['standard', 'booktabs','nolines'], 'default': 'standard',
120           'metavar': '<format>'}),
121         ('LaTeX graphicx package option. '
122          'Possible values are "dvips", "pdftex". "auto" includes LaTeX code '
123          'to use "pdftex" if processing with pdf(la)tex and dvips otherwise. '
124          'Default is no option.',
125          ['--graphicx-option'],
126          {'default': ''}),
127         ('LaTeX font encoding. '
128          'Possible values are "T1", "OT1", "" or some other fontenc option. '
129          'The font encoding influences available symbols, e.g. "<<" as one '
130          'character. Default is "" which leads to package "ae" (a T1 '
131          'emulation using CM fonts).',
132          ['--font-encoding'],
133          {'default': ''}),
134          ),)
135
136    settings_defaults = {'output_encoding': 'latin-1'}
137
138    relative_path_settings = ('stylesheet_path',)
139
140    config_section = 'latex2e writer'
141    config_section_dependencies = ('writers',)
142
143    output = None
144    """Final translated form of `document`."""
145
146    def __init__(self):
147        writers.Writer.__init__(self)
148        self.translator_class = LaTeXTranslator
149
150    def translate(self):
151        visitor = self.translator_class(self.document)
152        self.document.walkabout(visitor)
153        self.output = visitor.astext()
154        self.head_prefix = visitor.head_prefix
155        self.head = visitor.head
156        self.body_prefix = visitor.body_prefix
157        self.body = visitor.body
158        self.body_suffix = visitor.body_suffix
159
160"""
161Notes on LaTeX
162--------------
163
164* latex does not support multiple tocs in one document.
165  (might be no limitation except for docutils documentation)
166
167* width
168
169  * linewidth - width of a line in the local environment
170  * textwidth - the width of text on the page
171
172  Maybe always use linewidth ?
173
174  *Bug* inside a minipage a (e.g. Sidebar) the linewidth is
175        not changed, needs fix in docutils so that tables
176        are not too wide.
177
178        So we add locallinewidth set it initially and
179        on entering sidebar and reset on exit.
180"""
181
182class Babel:
183    """Language specifics for LaTeX."""
184    # country code by a.schlock.
185    # partly manually converted from iso and babel stuff, dialects and some
186    _ISO639_TO_BABEL = {
187        'no': 'norsk',     #XXX added by hand ( forget about nynorsk?)
188        'gd': 'scottish',  #XXX added by hand
189        'hu': 'magyar',    #XXX added by hand
190        'pt': 'portuguese',#XXX added by hand
191        'sl': 'slovenian',
192        'af': 'afrikaans',
193        'bg': 'bulgarian',
194        'br': 'breton',
195        'ca': 'catalan',
196        'cs': 'czech',
197        'cy': 'welsh',
198        'da': 'danish',
199        'fr': 'french',
200        # french, francais, canadien, acadian
201        'de': 'ngerman',  #XXX rather than german
202        # ngerman, naustrian, german, germanb, austrian
203        'el': 'greek',
204        'en': 'english',
205        # english, USenglish, american, UKenglish, british, canadian
206        'eo': 'esperanto',
207        'es': 'spanish',
208        'et': 'estonian',
209        'eu': 'basque',
210        'fi': 'finnish',
211        'ga': 'irish',
212        'gl': 'galician',
213        'he': 'hebrew',
214        'hr': 'croatian',
215        'hu': 'hungarian',
216        'is': 'icelandic',
217        'it': 'italian',
218        'la': 'latin',
219        'nl': 'dutch',
220        'pl': 'polish',
221        'pt': 'portuguese',
222        'ro': 'romanian',
223        'ru': 'russian',
224        'sk': 'slovak',
225        'sr': 'serbian',
226        'sv': 'swedish',
227        'tr': 'turkish',
228        'uk': 'ukrainian'
229    }
230
231    def __init__(self,lang):
232        self.language = lang
233        # pdflatex does not produce double quotes for ngerman in tt.
234        self.double_quote_replacment = None
235        if re.search('^de',self.language):
236            #self.quotes = ("\"`", "\"'")
237            self.quotes = ('{\\glqq}', '{\\grqq}')
238            self.double_quote_replacment = "{\\dq}"
239        else:
240            self.quotes = ("``", "''")
241        self.quote_index = 0
242
243    def next_quote(self):
244        q = self.quotes[self.quote_index]
245        self.quote_index = (self.quote_index+1)%2
246        return q
247
248    def quote_quotes(self,text):
249        t = None
250        for part in text.split('"'):
251            if t == None:
252                t = part
253            else:
254                t += self.next_quote() + part
255        return t
256
257    def double_quotes_in_tt (self,text):
258        if not self.double_quote_replacment:
259            return text
260        return text.replace('"', self.double_quote_replacment)
261
262    def get_language(self):
263        if self._ISO639_TO_BABEL.has_key(self.language):
264            return self._ISO639_TO_BABEL[self.language]
265        else:
266            # support dialects.
267            l = self.language.split("_")[0]
268            if self._ISO639_TO_BABEL.has_key(l):
269                return self._ISO639_TO_BABEL[l]
270        return None
271
272
273latex_headings = {
274        'optionlist_environment' : [
275              '\\newcommand{\\optionlistlabel}[1]{\\bf #1 \\hfill}\n'
276              '\\newenvironment{optionlist}[1]\n'
277              '{\\begin{list}{}\n'
278              '  {\\setlength{\\labelwidth}{#1}\n'
279              '   \\setlength{\\rightmargin}{1cm}\n'
280              '   \\setlength{\\leftmargin}{\\rightmargin}\n'
281              '   \\addtolength{\\leftmargin}{\\labelwidth}\n'
282              '   \\addtolength{\\leftmargin}{\\labelsep}\n'
283              '   \\renewcommand{\\makelabel}{\\optionlistlabel}}\n'
284              '}{\\end{list}}\n',
285              ],
286        'lineblock_environment' : [
287            '\\newlength{\\lineblockindentation}\n'
288            '\\setlength{\\lineblockindentation}{2.5em}\n'
289            '\\newenvironment{lineblock}[1]\n'
290            '{\\begin{list}{}\n'
291            '  {\\setlength{\\partopsep}{\\parskip}\n'
292            '   \\addtolength{\\partopsep}{\\baselineskip}\n'
293            '   \\topsep0pt\\itemsep0.15\\baselineskip\\parsep0pt\n'
294            '   \\leftmargin#1}\n'
295            ' \\raggedright}\n'
296            '{\\end{list}}\n'
297            ],
298        'footnote_floats' : [
299            '% begin: floats for footnotes tweaking.\n',
300            '\\setlength{\\floatsep}{0.5em}\n',
301            '\\setlength{\\textfloatsep}{\\fill}\n',
302            '\\addtolength{\\textfloatsep}{3em}\n',
303            '\\renewcommand{\\textfraction}{0.5}\n',
304            '\\renewcommand{\\topfraction}{0.5}\n',
305            '\\renewcommand{\\bottomfraction}{0.5}\n',
306            '\\setcounter{totalnumber}{50}\n',
307            '\\setcounter{topnumber}{50}\n',
308            '\\setcounter{bottomnumber}{50}\n',
309            '% end floats for footnotes\n',
310            ],
311        'some_commands' : [
312            '% some commands, that could be overwritten in the style file.\n'
313            '\\newcommand{\\rubric}[1]'
314            '{\\subsection*{~\\hfill {\\it #1} \\hfill ~}}\n'
315            '\\newcommand{\\titlereference}[1]{\\textsl{#1}}\n'
316            '% end of "some commands"\n',
317            ]
318        }
319
320class DocumentClass:
321    """Details of a LaTeX document class."""
322
323    # BUG: LaTeX has no deeper sections (actually paragrah is no
324    # section either).
325    # BUG: No support for unknown document classes.  Make 'article'
326    # default?
327    _class_sections = {
328        'book': ( 'chapter', 'section', 'subsection', 'subsubsection' ),
329        'scrbook': ( 'chapter', 'section', 'subsection', 'subsubsection' ),
330        'report': ( 'chapter', 'section', 'subsection', 'subsubsection' ),
331        'scrreprt': ( 'chapter', 'section', 'subsection', 'subsubsection' ),
332        'article': ( 'section', 'subsection', 'subsubsection' ),
333        'scrartcl': ( 'section', 'subsection', 'subsubsection' ),
334        }
335    _deepest_section = 'subsubsection'
336
337    def __init__(self, document_class):
338        self.document_class = document_class
339
340    def section(self, level):
341        """ Return the section name at the given level for the specific
342            document class.
343
344            Level is 1,2,3..., as level 0 is the title."""
345
346        sections = self._class_sections[self.document_class]
347        if level <= len(sections):
348            return sections[level-1]
349        else:
350            return self._deepest_section
351
352class Table:
353    """ Manage a table while traversing.
354        Maybe change to a mixin defining the visit/departs, but then
355        class Table internal variables are in the Translator.
356    """
357    def __init__(self,latex_type,table_style):
358        self._latex_type = latex_type
359        self._table_style = table_style
360        self._open = 0
361        # miscellaneous attributes
362        self._attrs = {}
363        self._col_width = []
364        self._rowspan = []
365
366    def open(self):
367        self._open = 1
368        self._col_specs = []
369        self.caption = None
370        self._attrs = {}
371        self._in_head = 0 # maybe context with search
372    def close(self):
373        self._open = 0
374        self._col_specs = None
375        self.caption = None
376        self._attrs = {}
377    def is_open(self):
378        return self._open
379    def used_packages(self):
380        if self._table_style == 'booktabs':
381            return '\\usepackage{booktabs}\n'
382        return ''
383    def get_latex_type(self):
384        return self._latex_type
385
386    def set(self,attr,value):
387        self._attrs[attr] = value
388    def get(self,attr):
389        if self._attrs.has_key(attr):
390            return self._attrs[attr]
391        return None
392    def get_vertical_bar(self):
393        if self._table_style == 'standard':
394            return '|'
395        return ''
396    # horizontal lines are drawn below a row, because we.
397    def get_opening(self):
398        return '\\begin{%s}[c]' % self._latex_type
399    def get_closing(self):
400        line = ""
401        if self._table_style == 'booktabs':
402            line = '\\bottomrule\n'
403        elif self._table_style == 'standard':
404            lines = '\\hline\n'
405        return '%s\\end{%s}' % (line,self._latex_type)
406
407    def visit_colspec(self,node):
408        self._col_specs.append(node)
409
410    def get_colspecs(self):
411        """
412        Return column specification for longtable.
413
414        Assumes reST line length being 80 characters.
415        Table width is hairy.
416
417        === ===
418        ABC DEF
419        === ===
420
421        usually gets to narrow, therefore we add 1 (fiddlefactor).
422        """
423        width = 80
424
425        total_width = 0.0
426        # first see if we get too wide.
427        for node in self._col_specs:
428            colwidth = float(node['colwidth']+1) / width
429            total_width += colwidth
430        self._col_width = []
431        self._rowspan = []
432        # donot make it full linewidth
433        factor = 0.93
434        if total_width > 1.0:
435            factor /= total_width
436        bar = self.get_vertical_bar()
437        latex_table_spec = ""
438        for node in self._col_specs:
439            colwidth = factor * float(node['colwidth']+1) / width
440            self._col_width.append(colwidth+0.005)
441            self._rowspan.append(0)
442            latex_table_spec += "%sp{%.2f\\locallinewidth}" % (bar,colwidth+0.005)
443        return latex_table_spec+bar
444
445    def get_column_width(self):
446        """ return columnwidth for current cell (not multicell)
447        """
448        return "%.2f\\locallinewidth" % self._col_width[self._cell_in_row-1]
449
450    def visit_thead(self):
451        self._in_thead = 1
452        if self._table_style == 'standard':
453            return ['\\hline\n']
454        elif self._table_style == 'booktabs':
455            return ['\\toprule\n']
456        return []
457    def depart_thead(self):
458        a = []
459        #if self._table_style == 'standard':
460        #    a.append('\\hline\n')
461        if self._table_style == 'booktabs':
462            a.append('\\midrule\n')
463        a.append('\\endhead\n')
464        # for longtable one could add firsthead, foot and lastfoot
465        self._in_thead = 0
466        return a
467    def visit_row(self):
468        self._cell_in_row = 0
469    def depart_row(self):
470        res = [' \\\\\n']
471        self._cell_in_row = None  # remove cell counter
472        for i in range(len(self._rowspan)):
473            if (self._rowspan[i]>0):
474                self._rowspan[i] -= 1
475
476        if self._table_style == 'standard':
477            rowspans = []
478            for i in range(len(self._rowspan)):
479                if (self._rowspan[i]<=0):
480                    rowspans.append(i+1)
481            if len(rowspans)==len(self._rowspan):
482                res.append('\\hline\n')
483            else:
484                cline = ''
485                rowspans.reverse()
486                # TODO merge clines
487                while 1:
488                    try:
489                        c_start = rowspans.pop()
490                    except:
491                        break
492                    cline += '\\cline{%d-%d}\n' % (c_start,c_start)
493                res.append(cline)
494        return res
495
496    def set_rowspan(self,cell,value):
497        try:
498            self._rowspan[cell] = value
499        except:
500            pass
501    def get_rowspan(self,cell):
502        try:
503            return self._rowspan[cell]
504        except:
505            return 0
506    def get_entry_number(self):
507        return self._cell_in_row
508    def visit_entry(self):
509        self._cell_in_row += 1
510
511
512class LaTeXTranslator(nodes.NodeVisitor):
513
514    # When options are given to the documentclass, latex will pass them
515    # to other packages, as done with babel.
516    # Dummy settings might be taken from document settings
517
518    latex_head = '\\documentclass[%s]{%s}\n'
519    encoding = '\\usepackage[%s]{inputenc}\n'
520    linking = '\\usepackage[colorlinks=%s,linkcolor=%s,urlcolor=%s]{hyperref}\n'
521    stylesheet = '\\input{%s}\n'
522    # add a generated on day , machine by user using docutils version.
523    generator = '%% generator Docutils: http://docutils.sourceforge.net/\n'
524
525    # use latex tableofcontents or let docutils do it.
526    use_latex_toc = 0
527
528    # TODO: use mixins for different implementations.
529    # list environment for option-list. else tabularx
530    use_optionlist_for_option_list = 1
531    # list environment for docinfo. else tabularx
532    use_optionlist_for_docinfo = 0 # NOT YET IN USE
533
534    # Use compound enumerations (1.A.1.)
535    compound_enumerators = 0
536
537    # If using compound enumerations, include section information.
538    section_prefix_for_enumerators = 0
539
540    # This is the character that separates the section ("." subsection ...)
541    # prefix from the regular list enumerator.
542    section_enumerator_separator = '-'
543
544    # default link color
545    hyperlink_color = "blue"
546
547    def __init__(self, document):
548        nodes.NodeVisitor.__init__(self, document)
549        self.settings = settings = document.settings
550        self.latex_encoding = self.to_latex_encoding(settings.output_encoding)
551        self.use_latex_toc = settings.use_latex_toc
552        self.use_latex_docinfo = settings.use_latex_docinfo
553        self.use_latex_footnotes = settings.use_latex_footnotes
554        self._use_latex_citations = settings.use_latex_citations
555        self.hyperlink_color = settings.hyperlink_color
556        self.compound_enumerators = settings.compound_enumerators
557        self.font_encoding = settings.font_encoding
558        self.section_prefix_for_enumerators = (
559            settings.section_prefix_for_enumerators)
560        self.section_enumerator_separator = (
561            settings.section_enumerator_separator.replace('_', '\\_'))
562        if self.hyperlink_color == '0':
563            self.hyperlink_color = 'black'
564            self.colorlinks = 'false'
565        else:
566            self.colorlinks = 'true'
567
568        # language: labels, bibliographic_fields, and author_separators.
569        # to allow writing labes for specific languages.
570        self.language = languages.get_language(settings.language_code)
571        self.babel = Babel(settings.language_code)
572        self.author_separator = self.language.author_separators[0]
573        self.d_options = self.settings.documentoptions
574        if self.babel.get_language():
575            self.d_options += ',%s' % \
576                    self.babel.get_language()
577
578        self.d_class = DocumentClass(settings.documentclass)
579        # object for a table while proccessing.
580        self.active_table = Table('longtable',settings.table_style)
581
582        # HACK.  Should have more sophisticated typearea handling.
583        if settings.documentclass.find('scr') == -1:
584            self.typearea = '\\usepackage[DIV12]{typearea}\n'
585        else:
586            if self.d_options.find('DIV') == -1 and self.d_options.find('BCOR') == -1:
587                self.typearea = '\\typearea{12}\n'
588            else:
589                self.typearea = ''
590
591        if self.font_encoding == 'OT1':
592            fontenc_header = ''
593        elif self.font_encoding == '':
594            fontenc_header = '\\usepackage{ae}\n\\usepackage{aeguill}\n'
595        else:
596            fontenc_header = '\\usepackage[%s]{fontenc}\n' % (self.font_encoding,)
597        input_encoding = self.encoding % self.latex_encoding
598        if self.settings.graphicx_option == '':
599            self.graphicx_package = '\\usepackage{graphicx}\n'
600        elif self.settings.graphicx_option.lower() == 'auto':
601            self.graphicx_package = '\n'.join(
602                ('%Check if we are compiling under latex or pdflatex',
603                 '\\ifx\\pdftexversion\\undefined',
604                 '  \\usepackage{graphicx}',
605                 '\\else',
606                 '  \\usepackage[pdftex]{graphicx}',
607                 '\\fi\n'))
608        else:
609            self.graphicx_package = (
610                '\\usepackage[%s]{graphicx}\n' % self.settings.graphicx_option)
611
612        self.head_prefix = [
613              self.latex_head % (self.d_options,self.settings.documentclass),
614              '\\usepackage{babel}\n',     # language is in documents settings.
615              fontenc_header,
616              '\\usepackage{shortvrb}\n',  # allows verb in footnotes.
617              input_encoding,
618              # * tabularx: for docinfo, automatic width of columns, always on one page.
619              '\\usepackage{tabularx}\n',
620              '\\usepackage{longtable}\n',
621              self.active_table.used_packages(),
622              # possible other packages.
623              # * fancyhdr
624              # * ltxtable is a combination of tabularx and longtable (pagebreaks).
625              #   but ??
626              #
627              # extra space between text in tables and the line above them
628              '\\setlength{\\extrarowheight}{2pt}\n',
629              '\\usepackage{amsmath}\n',   # what fore amsmath.
630              self.graphicx_package,
631              '\\usepackage{color}\n',
632              '\\usepackage{multirow}\n',
633              '\\usepackage{ifthen}\n',   # before hyperref!
634              self.linking % (self.colorlinks, self.hyperlink_color, self.hyperlink_color),
635              self.typearea,
636              self.generator,
637              # latex lengths
638              '\\newlength{\\admonitionwidth}\n',
639              '\\setlength{\\admonitionwidth}{0.9\\textwidth}\n'
640              # width for docinfo tablewidth
641              '\\newlength{\\docinfowidth}\n',
642              '\\setlength{\\docinfowidth}{0.9\\textwidth}\n'
643              # linewidth of current environment, so tables are not wider
644              # than the sidebar: using locallinewidth seems to defer evaluation
645              # of linewidth, this is fixing it.
646              '\\newlength{\\locallinewidth}\n',
647              # will be set later.
648              ]
649        self.head_prefix.extend( latex_headings['optionlist_environment'] )
650        self.head_prefix.extend( latex_headings['lineblock_environment'] )
651        self.head_prefix.extend( latex_headings['footnote_floats'] )
652        self.head_prefix.extend( latex_headings['some_commands'] )
653        ## stylesheet is last: so it might be possible to overwrite defaults.
654        stylesheet = utils.get_stylesheet_reference(settings)
655        if stylesheet:
656            settings.record_dependencies.add(stylesheet)
657            self.head_prefix.append(self.stylesheet % (stylesheet))
658
659        if self.linking: # and maybe check for pdf
660            self.pdfinfo = [ ]
661            self.pdfauthor = None
662            # pdftitle, pdfsubject, pdfauthor, pdfkeywords, pdfcreator, pdfproducer
663        else:
664            self.pdfinfo = None
665        # NOTE: Latex wants a date and an author, rst puts this into
666        #   docinfo, so normally we donot want latex author/date handling.
667        # latex article has its own handling of date and author, deactivate.
668        # So we always emit \title{...} \author{...} \date{...}, even if the
669        # "..." are empty strings.
670        self.head = [ ]
671        # separate title, so we can appen subtitle.
672        self.title = ''
673        # if use_latex_docinfo: collects lists of author/organization/contact/address lines
674        self.author_stack = []
675        self.date = ''
676
677        self.body_prefix = ['\\raggedbottom\n']
678        self.body = []
679        self.body_suffix = ['\n']
680        self.section_level = 0
681        self.context = []
682        self.topic_classes = []
683        # column specification for tables
684        self.table_caption = None
685       
686        # Flags to encode
687        # ---------------
688        # verbatim: to tell encode not to encode.
689        self.verbatim = 0
690        # insert_newline: to tell encode to replace blanks by "~".
691        self.insert_none_breaking_blanks = 0
692        # insert_newline: to tell encode to add latex newline.
693        self.insert_newline = 0
694        # mbox_newline: to tell encode to add mbox and newline.
695        self.mbox_newline = 0
696
697        # enumeration is done by list environment.
698        self._enum_cnt = 0
699
700        # Stack of section counters so that we don't have to use_latex_toc.
701        # This will grow and shrink as processing occurs.
702        # Initialized for potential first-level sections.
703        self._section_number = [0]
704
705        # The current stack of enumerations so that we can expand
706        # them into a compound enumeration
707        self._enumeration_counters = []
708
709        self._bibitems = []
710
711        # docinfo.
712        self.docinfo = None
713        # inside literal block: no quote mangling.
714        self.literal_block = 0
715        self.literal_block_stack = []
716        self.literal = 0
717        # true when encoding in math mode
718        self.mathmode = 0
719
720    def to_latex_encoding(self,docutils_encoding):
721        """
722        Translate docutils encoding name into latex's.
723
724        Default fallback method is remove "-" and "_" chars from docutils_encoding.
725
726        """
727        tr = {  "iso-8859-1": "latin1",     # west european
728                "iso-8859-2": "latin2",     # east european
729                "iso-8859-3": "latin3",     # esperanto, maltese
730                "iso-8859-4": "latin4",     # north european,scandinavian, baltic
731                "iso-8859-5": "iso88595",   # cyrillic (ISO)
732                "iso-8859-9": "latin5",     # turkish
733                "iso-8859-15": "latin9",    # latin9, update to latin1.
734                "mac_cyrillic": "maccyr",   # cyrillic (on Mac)
735                "windows-1251": "cp1251",   # cyrillic (on Windows)
736                "koi8-r": "koi8-r",         # cyrillic (Russian)
737                "koi8-u": "koi8-u",         # cyrillic (Ukrainian)
738                "windows-1250": "cp1250",   #
739                "windows-1252": "cp1252",   #
740                "us-ascii": "ascii",        # ASCII (US)
741                # unmatched encodings
742                #"": "applemac",
743                #"": "ansinew",  # windows 3.1 ansi
744                #"": "ascii",    # ASCII encoding for the range 32--127.
745                #"": "cp437",    # dos latine us
746                #"": "cp850",    # dos latin 1
747                #"": "cp852",    # dos latin 2
748                #"": "decmulti",
749                #"": "latin10",
750                #"iso-8859-6": ""   # arabic
751                #"iso-8859-7": ""   # greek
752                #"iso-8859-8": ""   # hebrew
753                #"iso-8859-10": ""   # latin6, more complete iso-8859-4
754             }
755        if tr.has_key(docutils_encoding.lower()):
756            return tr[docutils_encoding.lower()]
757        return docutils_encoding.translate(string.maketrans("",""),"_-").lower()
758
759    def language_label(self, docutil_label):
760        return self.language.labels[docutil_label]
761
762    latex_equivalents = {
763        u'\u00A0' : '~',
764        u'\u2013' : '{--}',
765        u'\u2014' : '{---}',
766        u'\u2018' : '`',
767        u'\u2019' : '\'',
768        u'\u201A' : ',',
769        u'\u201C' : '``',
770        u'\u201D' : '\'\'',
771        u'\u201E' : ',,',
772        u'\u2020' : '{\\dag}',
773        u'\u2021' : '{\\ddag}',
774        u'\u2026' : '{\\dots}',
775        u'\u2122' : '{\\texttrademark}',
776        u'\u21d4' : '{$\\Leftrightarrow$}',
777    }
778
779    def unicode_to_latex(self,text):
780        # see LaTeX codec
781        # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252124
782        # Only some special chracters are translated, for documents with many
783        # utf-8 chars one should use the LaTeX unicode package.
784        for uchar in self.latex_equivalents.keys():
785            text = text.replace(uchar,self.latex_equivalents[uchar])
786        return text
787
788    def encode(self, text):
789        """
790        Encode special characters (``# $ % & ~ _ ^ \ { }``) in `text` & return
791        """
792        # Escaping with a backslash does not help with backslashes, ~ and ^.
793
794        #     < > are only available in math-mode or tt font. (really ?)
795        #     $ starts math- mode.
796        # AND quotes
797        if self.verbatim:
798            return text
799        # compile the regexps once. do it here so one can see them.
800        #
801        # first the braces.
802        if not self.__dict__.has_key('encode_re_braces'):
803            self.encode_re_braces = re.compile(r'([{}])')
804        text = self.encode_re_braces.sub(r'{\\\1}',text)
805        if not self.__dict__.has_key('encode_re_bslash'):
806            # find backslash: except in the form '{\{}' or '{\}}'.
807            self.encode_re_bslash = re.compile(r'(?<!{)(\\)(?![{}]})')
808        # then the backslash: except in the form from line above:
809        # either '{\{}' or '{\}}'.
810        text = self.encode_re_bslash.sub(r'{\\textbackslash}', text)
811
812        # then dollar
813        text = text.replace("$", '{\\$}')
814        if not ( self.literal_block or self.literal or self.mathmode ):
815            # the vertical bar: in mathmode |,\vert or \mid
816            #   in textmode \textbar
817            text = text.replace("|", '{\\textbar}')
818            text = text.replace("<", '{\\textless}')
819            text = text.replace(">", '{\\textgreater}')
820        # then
821        text = text.replace("&", '{\\&}')
822        # the ^:
823        # * verb|^| does not work in mbox.
824        # * mathmode has wedge. hat{~} would also work.
825        # text = text.replace("^", '{\\ensuremath{^\\wedge}}')
826        text = text.replace("^", '{\\textasciicircum}')
827        text = text.replace("%", '{\\%}')
828        text = text.replace("#", '{\\#}')
829        text = text.replace("~", '{\\textasciitilde}')
830        # Separate compound characters, e.g. "--" to "-{}-".  (The
831        # actual separation is done later; see below.)
832        separate_chars = '-'
833        if self.literal_block or self.literal:
834            # In monospace-font, we also separate ",,", "``" and "''"
835            # and some other characters which can't occur in
836            # non-literal text.
837            separate_chars += ',`\'"<>'
838            # pdflatex does not produce doublequotes for ngerman.
839            text = self.babel.double_quotes_in_tt(text)
840            if self.font_encoding == 'OT1':
841                # We're using OT1 font-encoding and have to replace
842                # underscore by underlined blank, because this has
843                # correct width.
844                text = text.replace('_', '{\\underline{ }}')
845                # And the tt-backslash doesn't work in OT1, so we use
846                # a mirrored slash.
847                text = text.replace('\\textbackslash', '\\reflectbox{/}')
848            else:
849                text = text.replace('_', '{\\_}')
850        else:
851            text = self.babel.quote_quotes(text)
852            text = text.replace("_", '{\\_}')
853        for char in separate_chars * 2:
854            # Do it twice ("* 2") becaues otherwise we would replace
855            # "---" by "-{}--".
856            text = text.replace(char + char, char + '{}' + char)
857        if self.insert_newline or self.literal_block:
858            # Insert a blank before the newline, to avoid
859            # ! LaTeX Error: There's no line here to end.
860            text = text.replace("\n", '~\\\\\n')
861        elif self.mbox_newline:
862            if self.literal_block:
863                closings = "}" * len(self.literal_block_stack)
864                openings = "".join(self.literal_block_stack)
865            else:
866                closings = ""
867                openings = ""
868            text = text.replace("\n", "%s}\\\\\n\\mbox{%s" % (closings,openings))
869        text = text.replace('[', '{[}').replace(']', '{]}')
870        if self.insert_none_breaking_blanks:
871            text = text.replace(' ', '~')
872        if self.latex_encoding != 'utf8':
873            text = self.unicode_to_latex(text)
874        return text
875
876    def attval(self, text,
877               whitespace=re.compile('[\n\r\t\v\f]')):
878        """Cleanse, encode, and return attribute value text."""
879        return self.encode(whitespace.sub(' ', text))
880
881    def astext(self):
882        if self.pdfinfo is not None:
883            if self.pdfauthor:
884                self.pdfinfo.append('pdfauthor={%s}' % self.pdfauthor)
885        if self.pdfinfo:
886            pdfinfo = '\\hypersetup{\n' + ',\n'.join(self.pdfinfo) + '\n}\n'
887        else:
888            pdfinfo = ''
889        head = '\\title{%s}\n\\author{%s}\n\\date{%s}\n' % \
890               (self.title,
891                ' \\and\n'.join(['~\\\\\n'.join(author_lines)
892                                 for author_lines in self.author_stack]),
893                self.date)
894        return ''.join(self.head_prefix + [head] + self.head + [pdfinfo]
895                        + self.body_prefix  + self.body + self.body_suffix)
896
897    def visit_Text(self, node):
898        self.body.append(self.encode(node.astext()))
899
900    def depart_Text(self, node):
901        pass
902
903    def visit_address(self, node):
904        self.visit_docinfo_item(node, 'address')
905
906    def depart_address(self, node):
907        self.depart_docinfo_item(node)
908
909    def visit_admonition(self, node, name=''):
910        self.body.append('\\begin{center}\\begin{sffamily}\n')
911        self.body.append('\\fbox{\\parbox{\\admonitionwidth}{\n')
912        if name:
913            self.body.append('\\textbf{\\large '+ self.language.labels[name] + '}\n');
914        self.body.append('\\vspace{2mm}\n')
915
916
917    def depart_admonition(self, node=None):
918        self.body.append('}}\n') # end parbox fbox
919        self.body.append('\\end{sffamily}\n\\end{center}\n');
920
921    def visit_attention(self, node):
922        self.visit_admonition(node, 'attention')
923
924    def depart_attention(self, node):
925        self.depart_admonition()
926
927    def visit_author(self, node):
928        self.visit_docinfo_item(node, 'author')
929
930    def depart_author(self, node):
931        self.depart_docinfo_item(node)
932
933    def visit_authors(self, node):
934        # not used: visit_author is called anyway for each author.
935        pass
936
937    def depart_authors(self, node):
938        pass
939
940    def visit_block_quote(self, node):
941        self.body.append( '\\begin{quote}\n')
942
943    def depart_block_quote(self, node):
944        self.body.append( '\\end{quote}\n')
945
946    def visit_bullet_list(self, node):
947        if 'contents' in self.topic_classes:
948            if not self.use_latex_toc:
949                self.body.append( '\\begin{list}{}{}\n' )
950        else:
951            self.body.append( '\\begin{itemize}\n' )
952
953    def depart_bullet_list(self, node):
954        if 'contents' in self.topic_classes:
955            if not self.use_latex_toc:
956                self.body.append( '\\end{list}\n' )
957        else:
958            self.body.append( '\\end{itemize}\n' )
959
960    # Imperfect superscript/subscript handling: mathmode italicizes
961    # all letters by default.
962    def visit_superscript(self, node):
963        self.body.append('$^{')
964        self.mathmode = 1
965
966    def depart_superscript(self, node):
967        self.body.append('}$')
968        self.mathmode = 0
969
970    def visit_subscript(self, node):
971        self.body.append('$_{')
972        self.mathmode = 1
973
974    def depart_subscript(self, node):
975        self.body.append('}$')
976        self.mathmode = 0
977
978    def visit_caption(self, node):
979        self.body.append( '\\caption{' )
980
981    def depart_caption(self, node):
982        self.body.append('}')
983
984    def visit_caution(self, node):
985        self.visit_admonition(node, 'caution')
986
987    def depart_caution(self, node):
988        self.depart_admonition()
989
990    def visit_title_reference(self, node):
991        self.body.append( '\\titlereference{' )
992
993    def depart_title_reference(self, node):
994        self.body.append( '}' )
995
996    def visit_citation(self, node):
997        # TODO maybe use cite bibitems
998        if self._use_latex_citations:
999            self.context.append(len(self.body))
1000        else:
1001            self.body.append('\\begin{figure}[b]')
1002            for id in node['ids']:
1003                self.body.append('\\hypertarget{%s}' % id)
1004
1005    def depart_citation(self, node):
1006        if self._use_latex_citations:
1007            size = self.context.pop()
1008            label = self.body[size]
1009            text = ''.join(self.body[size+1:])
1010            del self.body[size:]
1011            self._bibitems.append([label, text])
1012        else:
1013            self.body.append('\\end{figure}\n')
1014
1015    def visit_citation_reference(self, node):
1016        if self._use_latex_citations:
1017            self.body.append('\\cite{')
1018        else:
1019            href = ''
1020            if node.has_key('refid'):
1021                href = node['refid']
1022            elif node.has_key('refname'):
1023                href = self.document.nameids[node['refname']]
1024            self.body.append('[\\hyperlink{%s}{' % href)
1025
1026    def depart_citation_reference(self, node):
1027        if self._use_latex_citations:
1028            self.body.append('}')
1029        else:
1030            self.body.append('}]')
1031
1032    def visit_classifier(self, node):
1033        self.body.append( '(\\textbf{' )
1034
1035    def depart_classifier(self, node):
1036        self.body.append( '})\n' )
1037
1038    def visit_colspec(self, node):
1039        self.active_table.visit_colspec(node)
1040
1041    def depart_colspec(self, node):
1042        pass
1043
1044    def visit_comment(self, node):
1045        # Escape end of line by a new comment start in comment text.
1046        self.body.append('%% %s \n' % node.astext().replace('\n', '\n% '))
1047        raise nodes.SkipNode
1048
1049    def visit_compound(self, node):
1050        pass
1051
1052    def depart_compound(self, node):
1053        pass
1054
1055    def visit_contact(self, node):
1056        self.visit_docinfo_item(node, 'contact')
1057
1058    def depart_contact(self, node):
1059        self.depart_docinfo_item(node)
1060
1061    def visit_container(self, node):
1062        pass
1063
1064    def depart_container(self, node):
1065        pass
1066
1067    def visit_copyright(self, node):
1068        self.visit_docinfo_item(node, 'copyright')
1069
1070    def depart_copyright(self, node):
1071        self.depart_docinfo_item(node)
1072
1073    def visit_danger(self, node):
1074        self.visit_admonition(node, 'danger')
1075
1076    def depart_danger(self, node):
1077        self.depart_admonition()
1078
1079    def visit_date(self, node):
1080        self.visit_docinfo_item(node, 'date')
1081
1082    def depart_date(self, node):
1083        self.depart_docinfo_item(node)
1084
1085    def visit_decoration(self, node):
1086        pass
1087
1088    def depart_decoration(self, node):
1089        pass
1090
1091    def visit_definition(self, node):
1092        self.body.append('%[visit_definition]\n')
1093
1094    def depart_definition(self, node):
1095        self.body.append('\n')
1096        self.body.append('%[depart_definition]\n')
1097
1098    def visit_definition_list(self, node):
1099        self.body.append( '\\begin{description}\n' )
1100
1101    def depart_definition_list(self, node):
1102        self.body.append( '\\end{description}\n' )
1103
1104    def visit_definition_list_item(self, node):
1105        self.body.append('%[visit_definition_list_item]\n')
1106
1107    def depart_definition_list_item(self, node):
1108        self.body.append('%[depart_definition_list_item]\n')
1109
1110    def visit_description(self, node):
1111        if self.use_optionlist_for_option_list:
1112            self.body.append( ' ' )
1113        else:
1114            self.body.append( ' & ' )
1115
1116    def depart_description(self, node):
1117        pass
1118
1119    def visit_docinfo(self, node):
1120        self.docinfo = []
1121        self.docinfo.append('%' + '_'*75 + '\n')
1122        self.docinfo.append('\\begin{center}\n')
1123        self.docinfo.append('\\begin{tabularx}{\\docinfowidth}{lX}\n')
1124
1125    def depart_docinfo(self, node):
1126        self.docinfo.append('\\end{tabularx}\n')
1127        self.docinfo.append('\\end{center}\n')
1128        self.body = self.docinfo + self.body
1129        # clear docinfo, so field names are no longer appended.
1130        self.docinfo = None
1131
1132    def visit_docinfo_item(self, node, name):
1133        if name == 'author':
1134            if not self.pdfinfo == None:
1135                if not self.pdfauthor:
1136                    self.pdfauthor = self.attval(node.astext())
1137                else:
1138                    self.pdfauthor += self.author_separator + self.attval(node.astext())
1139        if self.use_latex_docinfo:
1140            if name in ('author', 'organization', 'contact', 'address'):
1141                # We attach these to the last author.  If any of them precedes
1142                # the first author, put them in a separate "author" group (for
1143                # no better semantics).
1144                if name == 'author' or not self.author_stack:
1145                    self.author_stack.append([])
1146                if name == 'address':   # newlines are meaningful
1147                    self.insert_newline = 1
1148                    text = self.encode(node.astext())
1149                    self.insert_newline = 0
1150                else:
1151                    text = self.attval(node.astext())
1152                self.author_stack[-1].append(text)
1153                raise nodes.SkipNode
1154            elif name == 'date':
1155                self.date = self.attval(node.astext())
1156                raise nodes.SkipNode
1157        self.docinfo.append('\\textbf{%s}: &\n\t' % self.language_label(name))
1158        if name == 'address':
1159            self.insert_newline = 1
1160            self.docinfo.append('{\\raggedright\n')
1161            self.context.append(' } \\\\\n')
1162        else:
1163            self.context.append(' \\\\\n')
1164        self.context.append(self.docinfo)
1165        self.context.append(len(self.body))
1166
1167    def depart_docinfo_item(self, node):
1168        size = self.context.pop()
1169        dest = self.context.pop()
1170        tail = self.context.pop()
1171        tail = self.body[size:] + [tail]
1172        del self.body[size:]
1173        dest.extend(tail)
1174        # for address we did set insert_newline
1175        self.insert_newline = 0
1176
1177    def visit_doctest_block(self, node):
1178        self.body.append( '\\begin{verbatim}' )
1179        self.verbatim = 1
1180
1181    def depart_doctest_block(self, node):
1182        self.body.append( '\\end{verbatim}\n' )
1183        self.verbatim = 0
1184
1185    def visit_document(self, node):
1186        self.body_prefix.append('\\begin{document}\n')
1187        # titled document?
1188        if self.use_latex_docinfo or len(node) and isinstance(node[0], nodes.title):
1189            self.body_prefix.append('\\maketitle\n\n')
1190            # alternative use titlepage environment.
1191            # \begin{titlepage}
1192        self.body.append('\n\\setlength{\\locallinewidth}{\\linewidth}\n')
1193
1194    def depart_document(self, node):
1195        # TODO insertion point of bibliography should none automatic.
1196        if self._use_latex_citations and len(self._bibitems)>0:
1197            widest_label = ""
1198            for bi in self._bibitems:
1199                if len(widest_label)<len(bi[0]):
1200                    widest_label = bi[0]
1201            self.body.append('\n\\begin{thebibliography}{%s}\n'%widest_label)
1202            for bi in self._bibitems:
1203                # cite_key: underscores must not be escaped
1204                cite_key = bi[0].replace(r"{\_}","_")
1205                self.body.append('\\bibitem[%s]{%s}{%s}\n' % (bi[0], cite_key, bi[1]))
1206            self.body.append('\\end{thebibliography}\n')
1207
1208        self.body_suffix.append('\\end{document}\n')
1209
1210    def visit_emphasis(self, node):
1211        self.body.append('\\emph{')
1212        self.literal_block_stack.append('\\emph{')
1213
1214    def depart_emphasis(self, node):
1215        self.body.append('}')
1216        self.literal_block_stack.pop()
1217
1218    def visit_entry(self, node):
1219        self.active_table.visit_entry()
1220        # cell separation
1221        if self.active_table.get_entry_number() == 1:
1222            # if the firstrow is a multirow, this actually is the second row.
1223            # this gets hairy if rowspans follow each other.
1224            if self.active_table.get_rowspan(0):
1225                count = 0
1226                while self.active_table.get_rowspan(count):
1227                    count += 1
1228                    self.body.append(' & ')
1229                self.active_table.visit_entry() # increment cell count
1230        else:
1231            self.body.append(' & ')
1232
1233        # multi{row,column}
1234        # IN WORK BUG TODO HACK continues here
1235        # multirow in LaTeX simply will enlarge the cell over several rows
1236        # (the following n if n is positive, the former if negative).
1237        if node.has_key('morerows') and node.has_key('morecols'):
1238            raise NotImplementedError('Cells that '
1239            'span multiple rows *and* columns are not supported, sorry.')
1240        if node.has_key('morerows'):
1241            count = node['morerows'] + 1
1242            self.active_table.set_rowspan(self.active_table.get_entry_number()-1,count)
1243            self.body.append('\\multirow{%d}{%s}{' % \
1244                    (count,self.active_table.get_column_width()))
1245            self.context.append('}')
1246            # BUG following rows must have empty cells.
1247        elif node.has_key('morecols'):
1248            # the vertical bar before column is missing if it is the first column.
1249            # the one after always.
1250            if self.active_table.get_entry_number() == 1:
1251                bar1 = self.active_table.get_vertical_bar()
1252            else:
1253                bar1 = ''
1254            count = node['morecols'] + 1
1255            self.body.append('\\multicolumn{%d}{%sl%s}{' % \
1256                    (count, bar1, self.active_table.get_vertical_bar()))
1257            self.context.append('}')
1258        else:
1259            self.context.append('')
1260
1261        # header / not header
1262        if isinstance(node.parent.parent, nodes.thead):
1263            self.body.append('\\textbf{')
1264            self.context.append('}')
1265        else:
1266            self.context.append('')
1267
1268    def depart_entry(self, node):
1269        self.body.append(self.context.pop()) # header / not header
1270        self.body.append(self.context.pop()) # multirow/column
1271        # if following row is spanned from above.
1272        if self.active_table.get_rowspan(self.active_table.get_entry_number()):
1273           self.body.append(' & ')
1274           self.active_table.visit_entry() # increment cell count
1275
1276    def visit_row(self, node):
1277        self.active_table.visit_row()
1278
1279    def depart_row(self, node):
1280        self.body.extend(self.active_table.depart_row())
1281
1282    def visit_enumerated_list(self, node):
1283        # We create our own enumeration list environment.
1284        # This allows to set the style and starting value
1285        # and unlimited nesting.
1286        self._enum_cnt += 1
1287
1288        enum_style = {'arabic':'arabic',
1289                'loweralpha':'alph',
1290                'upperalpha':'Alph',
1291                'lowerroman':'roman',
1292                'upperroman':'Roman' }
1293        enum_suffix = ""
1294        if node.has_key('suffix'):
1295            enum_suffix = node['suffix']
1296        enum_prefix = ""
1297        if node.has_key('prefix'):
1298            enum_prefix = node['prefix']
1299        if self.compound_enumerators:
1300            pref = ""
1301            if self.section_prefix_for_enumerators and self.section_level:
1302                for i in range(self.section_level):
1303                    pref += '%d.' % self._section_number[i]
1304                pref = pref[:-1] + self.section_enumerator_separator
1305                enum_prefix += pref
1306            for counter in self._enumeration_counters:
1307                enum_prefix += counter + '.'
1308        enum_type = "arabic"
1309        if node.has_key('enumtype'):
1310            enum_type = node['enumtype']
1311        if enum_style.has_key(enum_type):
1312            enum_type = enum_style[enum_type]
1313        counter_name = "listcnt%d" % self._enum_cnt;
1314        self._enumeration_counters.append("\\%s{%s}" % (enum_type,counter_name))
1315        self.body.append('\\newcounter{%s}\n' % counter_name)
1316        self.body.append('\\begin{list}{%s\\%s{%s}%s}\n' % \
1317            (enum_prefix,enum_type,counter_name,enum_suffix))
1318        self.body.append('{\n')
1319        self.body.append('\\usecounter{%s}\n' % counter_name)
1320        # set start after usecounter, because it initializes to zero.
1321        if node.has_key('start'):
1322            self.body.append('\\addtocounter{%s}{%d}\n' \
1323                    % (counter_name,node['start']-1))
1324        ## set rightmargin equal to leftmargin
1325        self.body.append('\\setlength{\\rightmargin}{\\leftmargin}\n')
1326        self.body.append('}\n')
1327
1328    def depart_enumerated_list(self, node):
1329        self.body.append('\\end{list}\n')
1330        self._enumeration_counters.pop()
1331
1332    def visit_error(self, node):
1333        self.visit_admonition(node, 'error')
1334
1335    def depart_error(self, node):
1336        self.depart_admonition()
1337
1338    def visit_field(self, node):
1339        # real output is done in siblings: _argument, _body, _name
1340        pass
1341
1342    def depart_field(self, node):
1343        self.body.append('\n')
1344        ##self.body.append('%[depart_field]\n')
1345
1346    def visit_field_argument(self, node):
1347        self.body.append('%[visit_field_argument]\n')
1348
1349    def depart_field_argument(self, node):
1350        self.body.append('%[depart_field_argument]\n')
1351
1352    def visit_field_body(self, node):
1353        # BUG by attach as text we loose references.
1354        if self.docinfo:
1355            self.docinfo.append('%s \\\\\n' % self.encode(node.astext()))
1356            raise nodes.SkipNode
1357        # BUG: what happens if not docinfo
1358
1359    def depart_field_body(self, node):
1360        self.body.append( '\n' )
1361
1362    def visit_field_list(self, node):
1363        if not self.docinfo:
1364            self.body.append('\\begin{quote}\n')
1365            self.body.append('\\begin{description}\n')
1366
1367    def depart_field_list(self, node):
1368        if not self.docinfo:
1369            self.body.append('\\end{description}\n')
1370            self.body.append('\\end{quote}\n')
1371
1372    def visit_field_name(self, node):
1373        # BUG this duplicates docinfo_item
1374        if self.docinfo:
1375            self.docinfo.append('\\textbf{%s}: &\n\t' % self.encode(node.astext()))
1376            raise nodes.SkipNode
1377        else:
1378            self.body.append('\\item [')
1379
1380    def depart_field_name(self, node):
1381        if not self.docinfo:
1382            self.body.append(':]')
1383
1384    def visit_figure(self, node):
1385        if not node.attributes.has_key('align'):
1386            align = 'center'
1387        else:
1388            align = 'flush'+node.attributes['align']
1389        self.body.append( '\\begin{figure}[htbp]\\begin{%s}\n' % align )
1390        self.context.append( '\\end{%s}\\end{figure}\n' % align )
1391
1392    def depart_figure(self, node):
1393        self.body.append( self.context.pop() )
1394
1395    def visit_footer(self, node):
1396        self.context.append(len(self.body))
1397
1398    def depart_footer(self, node):
1399        start = self.context.pop()
1400        footer = (['\n\\begin{center}\small\n']
1401                  + self.body[start:] + ['\n\\end{center}\n'])
1402        self.body_suffix[:0] = footer
1403        del self.body[start:]
1404
1405    def visit_footnote(self, node):
1406        if self.use_latex_footnotes:
1407            num,text = node.astext().split(None,1)
1408            num = self.encode(num.strip())
1409            self.body.append('\\footnotetext['+num+']')
1410            self.body.append('{')
1411        else:
1412            self.body.append('\\begin{figure}[b]')
1413            for id in node['ids']:
1414                self.body.append('\\hypertarget{%s}' % id)
1415
1416    def depart_footnote(self, node):
1417        if self.use_latex_footnotes:
1418            self.body.append('}\n')
1419        else:
1420            self.body.append('\\end{figure}\n')
1421
1422    def visit_footnote_reference(self, node):
1423        if self.use_latex_footnotes:
1424            self.body.append("\\footnotemark["+self.encode(node.astext())+"]")
1425            raise nodes.SkipNode
1426        href = ''
1427        if node.has_key('refid'):
1428            href = node['refid']
1429        elif node.has_key('refname'):
1430            href = self.document.nameids[node['refname']]
1431        format = self.settings.footnote_references
1432        if format == 'brackets':
1433            suffix = '['
1434            self.context.append(']')
1435        elif format == 'superscript':
1436            suffix = '\\raisebox{.5em}[0em]{\\scriptsize'
1437            self.context.append('}')
1438        else:                           # shouldn't happen
1439            raise AssertionError('Illegal footnote reference format.')
1440        self.body.append('%s\\hyperlink{%s}{' % (suffix,href))
1441
1442    def depart_footnote_reference(self, node):
1443        if self.use_latex_footnotes:
1444            return
1445        self.body.append('}%s' % self.context.pop())
1446
1447    # footnote/citation label
1448    def label_delim(self, node, bracket, superscript):
1449        if isinstance(node.parent, nodes.footnote):
1450            if self.use_latex_footnotes:
1451                raise nodes.SkipNode
1452            if self.settings.footnote_references == 'brackets':
1453                self.body.append(bracket)
1454            else:
1455                self.body.append(superscript)
1456        else:
1457            assert isinstance(node.parent, nodes.citation)
1458            if not self._use_latex_citations:
1459                self.body.append(bracket)
1460
1461    def visit_label(self, node):
1462        self.label_delim(node, '[', '$^{')
1463
1464    def depart_label(self, node):
1465        self.label_delim(node, ']', '}$')
1466
1467    # elements generated by the framework e.g. section numbers.
1468    def visit_generated(self, node):
1469        pass
1470
1471    def depart_generated(self, node):
1472        pass
1473
1474    def visit_header(self, node):
1475        self.context.append(len(self.body))
1476
1477    def depart_header(self, node):
1478        start = self.context.pop()
1479        self.body_prefix.append('\n\\verb|begin_header|\n')
1480        self.body_prefix.extend(self.body[start:])
1481        self.body_prefix.append('\n\\verb|end_header|\n')
1482        del self.body[start:]
1483
1484    def visit_hint(self, node):
1485        self.visit_admonition(node, 'hint')
1486
1487    def depart_hint(self, node):
1488        self.depart_admonition()
1489
1490    def visit_image(self, node):
1491        attrs = node.attributes
1492        # Add image URI to dependency list, assuming that it's
1493        # referring to a local file.
1494        self.settings.record_dependencies.add(attrs['uri'])
1495        pre = []                        # in reverse order
1496        post = []
1497        include_graphics_options = ""
1498        inline = isinstance(node.parent, nodes.TextElement)
1499        if attrs.has_key('scale'):
1500            # Could also be done with ``scale`` option to
1501            # ``\includegraphics``; doing it this way for consistency.
1502            pre.append('\\scalebox{%f}{' % (attrs['scale'] / 100.0,))
1503            post.append('}')
1504        if attrs.has_key('width'):
1505            include_graphics_options = '[width=%s]' % attrs['width']
1506        if attrs.has_key('align'):
1507            align_prepost = {
1508                # By default latex aligns the top of an image.
1509                (1, 'top'): ('', ''),
1510                (1, 'middle'): ('\\raisebox{-0.5\\height}{', '}'),
1511                (1, 'bottom'): ('\\raisebox{-\\height}{', '}'),
1512                (0, 'center'): ('{\\hfill', '\\hfill}'),
1513                # These 2 don't exactly do the right thing.  The image should
1514                # be floated alongside the paragraph.  See
1515                # http://www.w3.org/TR/html4/struct/objects.html#adef-align-IMG
1516                (0, 'left'): ('{', '\\hfill}'),
1517                (0, 'right'): ('{\\hfill', '}'),}
1518            try:
1519                pre.append(align_prepost[inline, attrs['align']][0])
1520                post.append(align_prepost[inline, attrs['align']][1])
1521            except KeyError:
1522                pass                    # XXX complain here?
1523        if not inline:
1524            pre.append('\n')
1525            post.append('\n')
1526        pre.reverse()
1527        self.body.extend( pre )
1528        self.body.append( '\\includegraphics%s{%s}' % (
1529                include_graphics_options, attrs['uri'] ) )
1530        self.body.extend( post )
1531
1532    def depart_image(self, node):
1533        pass
1534
1535    def visit_important(self, node):
1536        self.visit_admonition(node, 'important')
1537
1538    def depart_important(self, node):
1539        self.depart_admonition()
1540
1541    def visit_interpreted(self, node):
1542        # @@@ Incomplete, pending a proper implementation on the
1543        # Parser/Reader end.
1544        self.visit_literal(node)
1545
1546    def depart_interpreted(self, node):
1547        self.depart_literal(node)
1548
1549    def visit_legend(self, node):
1550        self.body.append('{\\small ')
1551
1552    def depart_legend(self, node):
1553        self.body.append('}')
1554
1555    def visit_line(self, node):
1556        self.body.append('\item[] ')
1557
1558    def depart_line(self, node):
1559        self.body.append('\n')
1560
1561    def visit_line_block(self, node):
1562        if isinstance(node.parent, nodes.line_block):
1563            self.body.append('\\item[] \n'
1564                             '\\begin{lineblock}{\\lineblockindentation}\n')
1565        else:
1566            self.body.append('\n\\begin{lineblock}{0em}\n')
1567
1568    def depart_line_block(self, node):
1569        self.body.append('\\end{lineblock}\n')
1570
1571    def visit_list_item(self, node):
1572        # Append "{}" in case the next character is "[", which would break
1573        # LaTeX's list environment (no numbering and the "[" is not printed).
1574        self.body.append('\\item {} ')
1575
1576    def depart_list_item(self, node):
1577        self.body.append('\n')
1578
1579    def visit_literal(self, node):
1580        self.literal = 1
1581        self.body.append('\\texttt{')
1582
1583    def depart_literal(self, node):
1584        self.body.append('}')
1585        self.literal = 0
1586
1587    def visit_literal_block(self, node):
1588        """
1589        Render a literal-block.
1590
1591        Literal blocks are used for "::"-prefixed literal-indented
1592        blocks of text, where the inline markup is not recognized,
1593        but are also the product of the parsed-literal directive,
1594        where the markup is respected.
1595        """
1596        # In both cases, we want to use a typewriter/monospaced typeface.
1597        # For "real" literal-blocks, we can use \verbatim, while for all
1598        # the others we must use \mbox.
1599        #
1600        # We can distinguish between the two kinds by the number of
1601        # siblings the compose this node: if it is composed by a
1602        # single element, it's surely is either a real one, otherwise
1603        # it's a parsed-literal that does not contain any markup.
1604        #
1605        if (self.settings.use_verbatim_when_possible and (len(node) == 1)
1606              # in case of a parsed-literal containing just a "**bold**" word:
1607              and isinstance(node[0], nodes.Text)):
1608            self.verbatim = 1
1609            self.body.append('\\begin{quote}\\begin{verbatim}\n')
1610        else:
1611            self.literal_block = 1
1612            self.insert_none_breaking_blanks = 1
1613            if self.active_table.is_open():
1614                self.body.append('\n{\\ttfamily \\raggedright \\noindent\n')
1615            else:
1616                # no quote inside tables, to avoid vertical sppace between
1617                # table border and literal block.
1618                # BUG: fails if normal text preceeds the literal block.
1619                self.body.append('\\begin{quote}')
1620                self.body.append('{\\ttfamily \\raggedright \\noindent\n')
1621            # * obey..: is from julien and never worked for me (grubert).
1622            #   self.body.append('{\\obeylines\\obeyspaces\\ttfamily\n')
1623
1624    def depart_literal_block(self, node):
1625        if self.verbatim:
1626            self.body.append('\n\\end{verbatim}\\end{quote}\n')
1627            self.verbatim = 0
1628        else:
1629            if self.active_table.is_open():
1630                self.body.append('\n}\n')
1631            else:
1632                self.body.append('\n')
1633                self.body.append('}\\end{quote}\n')
1634            self.insert_none_breaking_blanks = 0
1635            self.literal_block = 0
1636            # obey end: self.body.append('}\n')
1637
1638    def visit_meta(self, node):
1639        self.body.append('[visit_meta]\n')
1640        # BUG maybe set keywords for pdf
1641        ##self.head.append(self.starttag(node, 'meta', **node.attributes))
1642
1643    def depart_meta(self, node):
1644        self.body.append('[depart_meta]\n')
1645
1646    def visit_note(self, node):
1647        self.visit_admonition(node, 'note')
1648
1649    def depart_note(self, node):
1650        self.depart_admonition()
1651
1652    def visit_option(self, node):
1653        if self.context[-1]:
1654            # this is not the first option
1655            self.body.append(', ')
1656
1657    def depart_option(self, node):
1658        # flag tha the first option is done.
1659        self.context[-1] += 1
1660
1661    def visit_option_argument(self, node):
1662        """The delimiter betweeen an option and its argument."""
1663        self.body.append(node.get('delimiter', ' '))
1664
1665    def depart_option_argument(self, node):
1666        pass
1667
1668    def visit_option_group(self, node):
1669        if self.use_optionlist_for_option_list:
1670            self.body.append('\\item [')
1671        else:
1672            if len(node.astext()) > 14:
1673                self.body.append('\\multicolumn{2}{l}{')
1674                self.context.append('} \\\\\n  ')
1675            else:
1676                self.context.append('')
1677            self.body.append('\\texttt{')
1678        # flag for first option
1679        self.context.append(0)
1680
1681    def depart_option_group(self, node):
1682        self.context.pop() # the flag
1683        if self.use_optionlist_for_option_list:
1684            self.body.append('] ')
1685        else:
1686            self.body.append('}')
1687            self.body.append(self.context.pop())
1688
1689    def visit_option_list(self, node):
1690        self.body.append('% [option list]\n')
1691        if self.use_optionlist_for_option_list:
1692            self.body.append('\\begin{optionlist}{3cm}\n')
1693        else:
1694            self.body.append('\\begin{center}\n')
1695            # BUG: use admwidth or make it relative to textwidth ?
1696            self.body.append('\\begin{tabularx}{.9\\linewidth}{lX}\n')
1697
1698    def depart_option_list(self, node):
1699        if self.use_optionlist_for_option_list:
1700            self.body.append('\\end{optionlist}\n')
1701        else:
1702            self.body.append('\\end{tabularx}\n')
1703            self.body.append('\\end{center}\n')
1704
1705    def visit_option_list_item(self, node):
1706        pass
1707
1708    def depart_option_list_item(self, node):
1709        if not self.use_optionlist_for_option_list:
1710            self.body.append('\\\\\n')
1711
1712    def visit_option_string(self, node):
1713        ##self.body.append(self.starttag(node, 'span', '', CLASS='option'))
1714        pass
1715
1716    def depart_option_string(self, node):
1717        ##self.body.append('</span>')
1718        pass
1719
1720    def visit_organization(self, node):
1721        self.visit_docinfo_item(node, 'organization')
1722
1723    def depart_organization(self, node):
1724        self.depart_docinfo_item(node)
1725
1726    def visit_paragraph(self, node):
1727        index = node.parent.index(node)
1728        if not ('contents' in self.topic_classes or
1729                (isinstance(node.parent, nodes.compound) and
1730                 index > 0 and
1731                 not isinstance(node.parent[index - 1], nodes.paragraph) and
1732                 not isinstance(node.parent[index - 1], nodes.compound))):
1733            self.body.append('\n')
1734
1735    def depart_paragraph(self, node):
1736        self.body.append('\n')
1737
1738    def visit_problematic(self, node):
1739        self.body.append('{\\color{red}\\bfseries{}')
1740
1741    def depart_problematic(self, node):
1742        self.body.append('}')
1743
1744    def visit_raw(self, node):
1745        if 'latex' in node.get('format', '').split():
1746            self.body.append(node.astext())
1747        raise nodes.SkipNode
1748
1749    def visit_reference(self, node):
1750        # BUG: hash_char "#" is trouble some in LaTeX.
1751        # mbox and other environment do not like the '#'.
1752        hash_char = '\\#'
1753        if node.has_key('refuri'):
1754            href = node['refuri'].replace('#',hash_char)
1755        elif node.has_key('refid'):
1756            href = hash_char + node['refid']
1757        elif node.has_key('refname'):
1758            href = hash_char + self.document.nameids[node['refname']]
1759        else:
1760            raise AssertionError('Unknown reference.')
1761        self.body.append('\\href{%s}{' % href)
1762
1763    def depart_reference(self, node):
1764        self.body.append('}')
1765
1766    def visit_revision(self, node):
1767        self.visit_docinfo_item(node, 'revision')
1768
1769    def depart_revision(self, node):
1770        self.depart_docinfo_item(node)
1771
1772    def visit_section(self, node):
1773        self.section_level += 1
1774        # Initialize counter for potential subsections:
1775        self._section_number.append(0)
1776        # Counter for this section's level (initialized by parent section):
1777        self._section_number[self.section_level - 1] += 1
1778
1779    def depart_section(self, node):
1780        # Remove counter for potential subsections:
1781        self._section_number.pop()
1782        self.section_level -= 1
1783
1784    def visit_sidebar(self, node):
1785        # BUG:  this is just a hack to make sidebars render something
1786        self.body.append('\n\\setlength{\\locallinewidth}{0.9\\admonitionwidth}\n')
1787        self.body.append('\\begin{center}\\begin{sffamily}\n')
1788        self.body.append('\\fbox{\\colorbox[gray]{0.80}{\\parbox{\\admonitionwidth}{\n')
1789
1790    def depart_sidebar(self, node):
1791        self.body.append('}}}\n') # end parbox colorbox fbox
1792        self.body.append('\\end{sffamily}\n\\end{center}\n');
1793        self.body.append('\n\\setlength{\\locallinewidth}{\\linewidth}\n')
1794
1795
1796    attribution_formats = {'dash': ('---', ''),
1797                           'parentheses': ('(', ')'),
1798                           'parens': ('(', ')'),
1799                           'none': ('', '')}
1800
1801    def visit_attribution(self, node):
1802        prefix, suffix = self.attribution_formats[self.settings.attribution]
1803        self.body.append('\n\\begin{flushright}\n')
1804        self.body.append(prefix)
1805        self.context.append(suffix)
1806
1807    def depart_attribution(self, node):
1808        self.body.append(self.context.pop() + '\n')
1809        self.body.append('\\end{flushright}\n')
1810
1811    def visit_status(self, node):
1812        self.visit_docinfo_item(node, 'status')
1813
1814    def depart_status(self, node):
1815        self.depart_docinfo_item(node)
1816
1817    def visit_strong(self, node):
1818        self.body.append('\\textbf{')
1819        self.literal_block_stack.append('\\textbf{')
1820
1821    def depart_strong(self, node):
1822        self.body.append('}')
1823        self.literal_block_stack.pop()
1824
1825    def visit_substitution_definition(self, node):
1826        raise nodes.SkipNode
1827
1828    def visit_substitution_reference(self, node):
1829        self.unimplemented_visit(node)
1830
1831    def visit_subtitle(self, node):
1832        if isinstance(node.parent, nodes.sidebar):
1833            self.body.append('~\\\\\n\\textbf{')
1834            self.context.append('}\n\\smallskip\n')
1835        elif isinstance(node.parent, nodes.document):
1836            self.title = self.title + \
1837                '\\\\\n\\large{%s}\n' % self.encode(node.astext())
1838            raise nodes.SkipNode
1839        elif isinstance(node.parent, nodes.section):
1840            self.body.append('\\textbf{')
1841            self.context.append('}\\vspace{0.2cm}\n\n\\noindent ')
1842
1843    def depart_subtitle(self, node):
1844        self.body.append(self.context.pop())
1845
1846    def visit_system_message(self, node):
1847        pass
1848
1849    def depart_system_message(self, node):
1850        self.body.append('\n')
1851
1852    def visit_table(self, node):
1853        if self.active_table.is_open():
1854            print 'nested tables are not supported'
1855            raise AssertionError
1856        self.active_table.open()
1857        self.body.append('\n' + self.active_table.get_opening())
1858
1859    def depart_table(self, node):
1860        self.body.append(self.active_table.get_closing() + '\n')
1861        self.active_table.close()
1862
1863    def visit_target(self, node):
1864        # BUG: why not (refuri or refid or refname) means not footnote ?
1865        if not (node.has_key('refuri') or node.has_key('refid')
1866                or node.has_key('refname')):
1867            for id in node['ids']:
1868                self.body.append('\\hypertarget{%s}{' % id)
1869            self.context.append('}' * len(node['ids']))
1870        else:
1871            self.context.append('')
1872
1873    def depart_target(self, node):
1874        self.body.append(self.context.pop())
1875
1876    def visit_tbody(self, node):
1877        # BUG write preamble if not yet done (colspecs not [])
1878        # for tables without heads.
1879        if not self.active_table.get('preamble written'):
1880            self.visit_thead(None)
1881            # self.depart_thead(None)
1882
1883    def depart_tbody(self, node):
1884        pass
1885
1886    def visit_term(self, node):
1887        self.body.append('\\item[{')
1888
1889    def depart_term(self, node):
1890        # definition list term.
1891        self.body.append('}] ')
1892
1893    def visit_tgroup(self, node):
1894        #self.body.append(self.starttag(node, 'colgroup'))
1895        #self.context.append('</colgroup>\n')
1896        pass
1897
1898    def depart_tgroup(self, node):
1899        pass
1900
1901    def visit_thead(self, node):
1902        self.body.append('{%s}\n' % self.active_table.get_colspecs())
1903        if self.active_table.caption:
1904            self.body.append('\\caption{%s}\\\\\n' % self.active_table.caption)
1905        self.active_table.set('preamble written',1)
1906        # TODO longtable supports firsthead and lastfoot too.
1907        self.body.extend(self.active_table.visit_thead())
1908
1909    def depart_thead(self, node):
1910        # the table header written should be on every page
1911        # => \endhead
1912        self.body.extend(self.active_table.depart_thead())
1913        # and the firsthead => \endfirsthead
1914        # BUG i want a "continued from previous page" on every not
1915        # firsthead, but then we need the header twice.
1916        #
1917        # there is a \endfoot and \endlastfoot too.
1918        # but we need the number of columns to
1919        # self.body.append('\\multicolumn{%d}{c}{"..."}\n' % number_of_columns)
1920        # self.body.append('\\hline\n\\endfoot\n')
1921        # self.body.append('\\hline\n')
1922        # self.body.append('\\endlastfoot\n')
1923
1924    def visit_tip(self, node):
1925        self.visit_admonition(node, 'tip')
1926
1927    def depart_tip(self, node):
1928        self.depart_admonition()
1929
1930    def bookmark(self, node):
1931        """Append latex href and pdfbookmarks for titles.
1932        """
1933        if node.parent['ids']:
1934            for id in node.parent['ids']:
1935                self.body.append('\\hypertarget{%s}{}\n' % id)
1936            if not self.use_latex_toc:
1937                # BUG level depends on style. pdflatex allows level 0 to 3
1938                # ToC would be the only on level 0 so i choose to decrement the rest.
1939                # "Table of contents" bookmark to see the ToC. To avoid this
1940                # we set all zeroes to one.
1941                l = self.section_level
1942                if l>0:
1943                    l = l-1
1944                # pdftex does not like "_" subscripts in titles
1945                text = self.encode(node.astext())
1946                for id in node.parent['ids']:
1947                    self.body.append('\\pdfbookmark[%d]{%s}{%s}\n' % \
1948                                     (l, text, id))
1949
1950    def visit_title(self, node):
1951        """Only 3 section levels are supported by LaTeX article (AFAIR)."""
1952
1953        if isinstance(node.parent, nodes.topic):
1954            # section titles before the table of contents.
1955            self.bookmark(node)
1956            # BUG: latex chokes on center environment with "perhaps a missing item".
1957            # so we use hfill.
1958            self.body.append('\\subsubsection*{~\\hfill ')
1959            # the closing brace for subsection.
1960            self.context.append('\\hfill ~}\n')
1961        # TODO: for admonition titles before the first section
1962        # either specify every possible node or ... ?
1963        elif isinstance(node.parent, nodes.sidebar) \
1964        or isinstance(node.parent, nodes.admonition):
1965            self.body.append('\\textbf{\\large ')
1966            self.context.append('}\n\\smallskip\n')
1967        elif isinstance(node.parent, nodes.table):
1968            # caption must be written after column spec
1969            self.active_table.caption = self.encode(node.astext())
1970            raise nodes.SkipNode
1971        elif self.section_level == 0:
1972            # document title
1973            self.title = self.encode(node.astext())
1974            if not self.pdfinfo == None:
1975                self.pdfinfo.append( 'pdftitle={%s}' % self.encode(node.astext()) )
1976            raise nodes.SkipNode
1977        else:
1978            self.body.append('\n\n')
1979            self.body.append('%' + '_' * 75)
1980            self.body.append('\n\n')
1981            self.bookmark(node)
1982
1983            if self.use_latex_toc:
1984                section_star = ""
1985            else:
1986                section_star = "*"
1987
1988            section_name = self.d_class.section(self.section_level)
1989            self.body.append('\\%s%s{' % (section_name, section_star))
1990
1991            self.context.append('}\n')
1992
1993    def depart_title(self, node):
1994        self.body.append(self.context.pop())
1995
1996    def visit_topic(self, node):
1997        self.topic_classes = node['classes']
1998        if 'contents' in node['classes'] and self.use_latex_toc:
1999            self.body.append('\\tableofcontents\n\n\\bigskip\n')
2000            self.topic_classes = []
2001            raise nodes.SkipNode
2002
2003    def visit_inline(self, node): # titlereference
2004        self.body.append( '\\docutilsrole%s{' % node.get('class'))
2005
2006    def depart_inline(self, node):
2007        self.body.append( '}' )
2008
2009    def depart_topic(self, node):
2010        self.topic_classes = []
2011        self.body.append('\n')
2012
2013    def visit_rubric(self, node):
2014        self.body.append('\\rubric{')
2015        self.context.append('}\n')
2016
2017    def depart_rubric(self, node):
2018        self.body.append(self.context.pop())
2019
2020    def visit_transition(self, node):
2021        self.body.append('\n\n')
2022        self.body.append('%' + '_' * 75)
2023        self.body.append('\n\\hspace*{\\fill}\\hrulefill\\hspace*{\\fill}')
2024        self.body.append('\n\n')
2025
2026    def depart_transition(self, node):
2027        pass
2028
2029    def visit_version(self, node):
2030        self.visit_docinfo_item(node, 'version')
2031
2032    def depart_version(self, node):
2033        self.depart_docinfo_item(node)
2034
2035    def visit_warning(self, node):
2036        self.visit_admonition(node, 'warning')
2037
2038    def depart_warning(self, node):
2039        self.depart_admonition()
2040
2041    def unimplemented_visit(self, node):
2042        raise NotImplementedError('visiting unimplemented node type: %s'
2043                                  % node.__class__.__name__)
2044
2045#    def unknown_visit(self, node):
2046#    def default_visit(self, node):
2047
2048# vim: set ts=4 et ai :
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。