[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gzz-commits] gzz/metacode latex-stripped.py
From: |
Asko Soukka |
Subject: |
[Gzz-commits] gzz/metacode latex-stripped.py |
Date: |
Wed, 05 Feb 2003 07:08:17 -0500 |
CVSROOT: /cvsroot/gzz
Module name: gzz
Changes by: Asko Soukka <address@hidden> 03/02/05 07:08:15
Modified files:
metacode : latex-stripped.py
Log message:
hups
CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/gzz/gzz/metacode/latex-stripped.py.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
Patches:
Index: gzz/metacode/latex-stripped.py
diff -u gzz/metacode/latex-stripped.py:1.1 gzz/metacode/latex-stripped.py:1.2
--- gzz/metacode/latex-stripped.py:1.1 Wed Feb 5 06:46:42 2003
+++ gzz/metacode/latex-stripped.py Wed Feb 5 07:08:15 2003
@@ -1,25 +1,1290 @@
-#!/usr/bin/env python
+#! /usr/bin/env python
-# Author: David Goodger
-# Contact: address@hidden
-# Revision: $Revision: 1.1 $
-# Date: $Date: 2003/02/05 11:46:42 $
-# Copyright: This module has been placed in the public domain.
+"""
+:Author: Engelbert Gruber
+:Contact: address@hidden
+:Revision: $Revision: 1.2 $
+:Date: $Date: 2003/02/05 12:08:15 $
+:Copyright: This module has been placed in the public domain.
+LaTeX2e document tree Writer.
"""
-A minimal front end to the Docutils Publisher, producing HTML.
+
+__docformat__ = 'reStructuredText'
+
+# convention deactivate code by two # e.g. ##.
+
+import sys
+import time
+import re
+import string
+from types import ListType
+from docutils import writers, nodes, languages
+
+# country code by a.schlock.
+# partly manually converted from iso and babel stuff, dialects and some
+# languages remain missing (austrian, UKEnglish, brazillian etc.)
+_ISO639_TO_BABEL = {
+ 'no': 'norsk', #XXX added by hand ( forget about nynorsk?)
+ 'gd': 'scottish', #XXX added by hand
+ 'hu': 'magyar', #XXX added by hand
+ 'pt': 'portuguese',#XXX added by hand
+ 'sl': 'slovenian',
+ 'af': 'afrikaans',
+ 'bg': 'bulgarian',
+ 'br': 'breton',
+ 'ca': 'catalan',
+ 'cs': 'czech',
+ 'cy': 'welsh',
+ 'da': 'danish',
+
+ 'de': 'ngerman', #XXX rather than german
+ 'el': 'greek',
+ 'en': 'english',
+ 'eo': 'esperanto',
+ 'es': 'spanish',
+ 'et': 'estonian',
+ 'eu': 'basque',
+ 'fi': 'finnish',
+ 'ga': 'irish',
+ 'gl': 'galician',
+ 'he': 'hebrew',
+ 'hr': 'croatian',
+ 'hu': 'hungarian',
+ 'is': 'icelandic',
+ 'it': 'italian',
+ 'la': 'latin',
+ 'nl': 'dutch',
+ 'pl': 'polish',
+ 'pt': 'portuguese',
+ 'ro': 'romanian',
+ 'ru': 'russian',
+ 'sk': 'slovak',
+ 'sr': 'serbian',
+ 'sv': 'swedish',
+ 'tr': 'turkish',
+ 'uk': 'ukrainian'
+ }
+
+class Writer(writers.Writer):
+
+ supported = ('latex','latex2e')
+ """Formats this writer supports."""
+
+ settings_spec = (
+ 'LaTeX-Specific Options',
+ 'The LaTeX "--output-encoding" default is "latin-1".',
+ (('Specify documentclass. Default is "article".',
+ ['--documentclass'],
+ {'default': 'article', }),
+ ('Format for footnote references: one of "superscript" or '
+ '"brackets". Default is "superscript".',
+ ['--footnote-references'],
+ {'choices': ['superscript', 'brackets'], 'default': 'brackets',
+ 'metavar': '<FORMAT>'}),
+ ('Link to the stylesheet in the output LaTeX file. This is the '
+ 'default.',
+ ['--link-stylesheet'],
+ {'dest': 'embed_stylesheet', 'action': 'store_false'}),
+ ('Embed the stylesheet in the output LaTeX file. The stylesheet '
+ 'file must be accessible during processing (--stylesheet-path is '
+ 'recommended).',
+ ['--embed-stylesheet'],
+ {'action': 'store_true'}),
+ ('Table of contents by docutils (default) or latex. Latex(writer)
supports only '
+ 'one ToC per document, but docutils does not write pagenumbers.',
+ ['--use-latex-toc'], {'default': 0}),
+ ))
+
+ settings_default_overrides = {'output_encoding': 'latin-1'}
+
+ output = None
+ """Final translated form of `document`."""
+
+ def translate(self):
+ visitor = LaTeXTranslator(self.document)
+ self.document.walkabout(visitor)
+ self.output = visitor.astext()
+ self.head_prefix = visitor.head_prefix
+ self.head = visitor.head
+ self.body_prefix = visitor.body_prefix
+ self.body = visitor.body
+ self.body_suffix = visitor.body_suffix
+
"""
+Notes on LaTeX
+--------------
+
+* Put labels inside environments::
+ \chapter[optional]{title}
+ \label{lab} % optional, for cross referencing
+ text for this unit ...
+* unnumbered sections are not written to tableofcontents.
+ a. donot print numbers::
+ \renewcommand{\thesection}{}
+ b. use::
+ \addcontentsline{file}{sec_unit}{entry}
+ file toc,lof lot
+ sec_unit section, subsection , ...
+ entry the line::
+ \numberline text pagenumber
+ X. latex does not support multiple tocs in one document.
+ (might be no limitation except for docutils documentation)
+
+* sectioning::
+ \part
+ \chapter (report style only)
+ \section
+ \subsection
+ \subsubsection
+ \paragraph
+ \subparagraph
+ \subsubparagraph (milstd and book-form styles only)
+ \subsubsubparagraph (milstd and book-form styles only)
+
+* documentclass options
+
+ all notitlepage.
+
+ article: 11pt, 12pt, twoside, twocolumn, draft, fleqn, leqno, acm
+
+ report: 11pt, 12pt, twoside, twocolumn, draft, fleqn, leqno, acm
+
+ letter: 11pt, 12pt, fleqn, leqno, acm
+
+ book: 11pt, 12pt, twoside,twocolumn, draft, fleqn, leqno
+
+* width
+
+ * linewidth - width of a line in the local environment
+ * textwidth - the width of text on the page
+
+ Maybe always use linewidth ?
+"""
+
+class Babel:
+ """Language specifics for LaTeX."""
+ def __init__(self,lang):
+ self.language = lang
+ if re.search('^de',self.language):
+ self.quotes = ("\"`", "\"'")
+ else:
+ self.quotes = ("``", "''")
+ self.quote_index = 0
+
+ def next_quote(self):
+ q = self.quotes[self.quote_index]
+ self.quote_index = (self.quote_index+1)%2
+ return q
+
+class LaTeXTranslator(nodes.NodeVisitor):
+ # When options are given to the documentclass, latex will pass them
+ # to other packages, as done with babel.
+ # Dummy settings might be taken from document settings
+
+ ## For narrower things (tables, docinfos use admwidth in latex construct).
+ d_class = 'acm_proc_article-sp' # document.settings.stylesheet
+ d_options = '10pt' # papersize, fontsize
+ d_paper = 'a4paper'
+ d_margins = '2cm'
+ d_stylesheet_path = 'acm_proc_article-sp.cls'
+ # for pdflatex some other package. pslatex
+
+#ACM latex_head = '\\documentclass[%s]{%s}\n'
+ latex_head = '\\documentclass{%s}\n'
+#ACM encoding = '\\usepackage[latin1]{inputenc}\n'
+#ACM linking = '\\usepackage[colorlinks,linkcolor=blue]{hyperref}\n'
+#ACM geometry = '\\usepackage[%s,margin=%s,nohead]{geometry}\n'
+ stylesheet = '\\input{%s}\n'
+ # add a generated on day , machine by user using docutils version.
+ generator = '%% generator Docutils: http://docutils.sourceforge.net/\n'
+
+ # use latex tableofcontents or let docutils do it.
+ use_latex_toc = 0
+ # table kind: if 0 tabularx (single page), 1 longtable
+ # maybe should be decided on row count.
+ use_longtable = 1
+ # TODO: use mixins for different implementations.
+ # list environment for option-list. else tabularx
+ use_optionlist_for_option_list = 1
+ # list environment for docinfo. else tabularx
+ use_optionlist_for_docinfo = 0 # NOT YET IN USE
+
+ def __init__(self, document):
+ nodes.NodeVisitor.__init__(self, document)
+ self.settings = settings = document.settings
+ self.use_latex_toc = settings.use_latex_toc
+ # language: labels, bibliographic_fields, and author_separators.
+ # to allow writing labes for specific languages.
+ self.language = languages.get_language(settings.language_code)
+ self.babel = Babel(settings.language_code)
+ self.author_separator = self.language.author_separators[0]
+ if _ISO639_TO_BABEL.has_key(settings.language_code):
+ self.d_options += ',%s' % \
+ _ISO639_TO_BABEL[settings.language_code]
+ self.head_prefix = [
+#ACM self.latex_head % (self.d_options,self.d_class),
+ self.latex_head % (self.d_class),
+#ACM '\\usepackage{babel}\n', # language is in documents
settings.
+#ACM '\\usepackage{shortvrb}\n', # allows verb in footnotes.
+#ACM self.encoding,
+ # * tabularx: for docinfo, automatic width of columns, always on
one page.
+#ACM '\\usepackage{tabularx}\n',
+#ACM '\\usepackage{longtable}\n',
+ # possible other packages.
+ # * fancyhdr
+ # * ltxtable is a combination of tabularx and longtable
(pagebreaks).
+ # but ??
+ #
+ # extra space between text in tables and the line above them
+#ACM '\\setlength{\\extrarowheight}{2pt}\n',
+#ACM '\\usepackage{amsmath}\n', # what fore amsmath.
+#ACM '\\usepackage{graphicx}\n',
+#ACM '\\usepackage{color}\n',
+#ACM '\\usepackage{multirow}\n',
+#ACM self.linking,
+ # geometry and fonts might go into style.tex.
+#ACM self.geometry % (self.d_paper, self.d_margins),
+ #
+#ACM self.generator,
+ # admonition width and docinfo tablewidth
+#ACM
'\\newlength{\\admwidth}\n\\addtolength{\\admwidth}{0.9\\textwidth}\n',
+ # optionlist environment
+#ACM '\\newcommand{\\optionlistlabel}[1]{\\bf #1 \\hfill}\n'
+#ACM '\\newenvironment{optionlist}[1]\n'
+#ACM '{\\begin{list}{}\n'
+#ACM ' {\\setlength{\\labelwidth}{#1}\n'
+#ACM ' \\setlength{\\rightmargin}{1cm}\n'
+#ACM ' \\setlength{\\leftmargin}{\\rightmargin}\n'
+#ACM ' \\addtolength{\\leftmargin}{\\labelwidth}\n'
+#ACM ' \\addtolength{\\leftmargin}{\\labelsep}\n'
+#ACM ' \\renewcommand{\\makelabel}{\\optionlistlabel}}\n'
+#ACM '}{\\end{list}}\n',
+ ## stylesheet is last: so it might be possible to overwrite
defaults.
+#ACM self.stylesheet % (self.d_stylesheet_path),
+ ]
+#ACM if self.linking: # and maybe check for pdf
+#ACM self.pdfinfo = [ ]
+#ACM self.pdfauthor = None
+ # pdftitle, pdfsubject, pdfauthor, pdfkeywords, pdfcreator,
pdfproducer
+#ACM else:
+#ACM self.pdfinfo = None
+#ACM self.pdfinfo = None
+ self.head = []
+#ACM self.body_prefix = ['\\raggedbottom\n']
+ self.body_prefix = []
+ # separate title, so we can appen subtitle.
+ self.title = ""
+ self.body = []
+ self.body_suffix = ['\n']
+ self.section_level = 0
+ self.context = []
+ self.topic_class = ''
+ # column specification for tables
+ self.colspecs = []
+ # verbatim: to tell encode not to encode.
+ self.verbatim = 0
+ # insert_newline: to tell encode to add newline.
+ self.insert_newline = 0
+ # mbox_newline: to tell encode to add mbox and newline.
+ self.mbox_newline = 0
+ # enumeration is done by list environment.
+ self._enum_cnt = 0
+
+ def language_label(self, docutil_label):
+ return self.language.labels[docutil_label]
+
+ def encode(self, text):
+ """
+ Encode special characters in `text` & return.
+ # $ % & ~ _ ^ \ { }
+ Escaping with a backslash does not help with backslashes, ~ and ^.
+
+ < > are only available in math-mode (really ?)
+ $ starts math- mode.
+ AND quotes:
+
+ """
+ if self.verbatim:
+ return text
+ # first the backslash
+ text = text.replace("\\", '{\\textbackslash}')
+ # then dollar
+ text = text.replace("$", '{\\$}')
+ # then all that needs math mode
+ text = text.replace("<", '{$<$}')
+ text = text.replace(">", '{$>$}')
+ # then
+ text = text.replace("&", '{\\&}')
+ text = text.replace("_", '{\\_}')
+ text = text.replace("^", '{\\verb|^|}') # ugly
+ text = text.replace("%", '{\\%}')
+ text = text.replace("#", '{\\#}')
+ text = text.replace("~", '{\\~{ }}')
+ t = None
+ for part in text.split('"'):
+ if t == None:
+ t = part
+ else:
+ t += self.babel.next_quote() + part
+ text = t
+ if self.insert_newline:
+ text = text.replace("\n", '\\\\\n')
+ elif self.mbox_newline:
+ text = text.replace("\n", '}\\\\\n\\mbox{')
+ text = text.replace(' ', '~')
+ # unicode !!!
+ text = text.replace(u'\u2020', '{$\\dagger$}')
+ return text
+
+ def attval(self, text,
+ whitespace=re.compile('[\n\r\t\v\f]')):
+ """Cleanse, encode, and return attribute value text."""
+ return self.encode(whitespace.sub(' ', text))
+
+ def astext(self):
+#ACM if self.pdfinfo:
+#ACM if self.pdfauthor:
+#ACM self.pdfinfo.append('pdfauthor={%s}' % self.pdfauthor)
+#ACM pdfinfo = '\\hypersetup{\n' + ',\n'.join(self.pdfinfo) +
'\n}\n'
+#ACM else:
+#ACM pdfinfo = ''
+ title = '\\title{%s}\n' % self.title
+#ACM return ''.join(self.head_prefix + [title] + self.head + [pdfinfo]
+#ACM + self.body_prefix + self.body + self.body_suffix)
+ return ''.join(self.head_prefix + self.head
+ + self.body_prefix + [title] + self.body +
self.body_suffix)
+
+ def visit_Text(self, node):
+ self.body.append(self.encode(node.astext()))
+
+ def depart_Text(self, node):
+ pass
+
+ def visit_address(self, node):
+ self.visit_docinfo_item(node, 'address')
+
+ def depart_address(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_admonition(self, node, name):
+ self.body.append('\\begin{center}\n');
+ # alternatives: parbox or minipage.
+ # minpage has footnotes on the minipage.
+ # BUG there is no border.
+#ACM self.body.append('\\parbox{\\admwidth}{\\textbf{'
+ self.body.append('\\parbox{\\textbf{'
+ + self.language.labels[name] + '}\n')
+
+ def depart_admonition(self):
+ self.body.append('}\n')
+ self.body.append('\\end{center}\n');
+
+ def visit_attention(self, node):
+ self.visit_admonition(node, 'attention')
+
+ def depart_attention(self, node):
+ self.depart_admonition()
+
+ def visit_author(self, node):
+ self.visit_docinfo_item(node, 'author')
+
+ def depart_author(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_authors(self, node):
+ # ignore. visit_author is called for each one
+ # self.visit_docinfo_item(node, 'author')
+ pass
+
+ def depart_authors(self, node):
+ # self.depart_docinfo_item(node)
+ pass
+
+ def visit_block_quote(self, node):
+ self.body.append( '\\begin{quote}\n')
+
+ def depart_block_quote(self, node):
+ self.body.append( '\\end{quote}\n')
+
+ def visit_bullet_list(self, node):
+ if not self.use_latex_toc and self.topic_class == 'contents':
+ self.body.append( '\\begin{list}{}{}\n' )
+ else:
+ self.body.append( '\\begin{itemize}\n' )
+
+ def depart_bullet_list(self, node):
+ if not self.use_latex_toc and self.topic_class == 'contents':
+ self.body.append( '\\end{list}\n' )
+ else:
+ self.body.append( '\\end{itemize}\n' )
+
+ def visit_caption(self, node):
+ self.body.append( '\\caption{' )
+
+ def depart_caption(self, node):
+ self.body.append('}')
+
+ def visit_caution(self, node):
+ self.visit_admonition(node, 'caution')
+
+ def depart_caution(self, node):
+ self.depart_admonition()
+
+ def visit_citation(self, node):
+ self.visit_footnote(node)
+
+ def depart_citation(self, node):
+ self.depart_footnote(node)
+
+ def visit_citation_reference(self, node):
+ pass
+#ACM href = ''
+#ACM if node.has_key('refid'):
+#ACM href = node['refid']
+#ACM elif node.has_key('refname'):
+#ACM href = self.document.nameids[node['refname']]
+#ACM self.body.append('[\\hyperlink{%s}{' % href)
+
+ def depart_citation_reference(self, node):
+ pass
+#ACM self.body.append('}]')
+
+ def visit_classifier(self, node):
+ self.body.append( '(\\textbf{' )
+
+ def depart_classifier(self, node):
+ self.body.append( '})\n' )
+
+ def visit_colspec(self, node):
+ if self.use_longtable:
+ self.colspecs.append(node)
+ else:
+ self.context[-1] += 1
+
+ def depart_colspec(self, node):
+ pass
+
+ def visit_comment(self, node,
+ sub=re.compile('\n').sub):
+ """Escape end of line by a ne comment start in comment text."""
+ self.body.append('%% %s \n' % sub('\n% ', node.astext()))
+ raise nodes.SkipNode
+
+ def visit_contact(self, node):
+ self.visit_docinfo_item(node, 'contact')
+
+ def depart_contact(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_copyright(self, node):
+ self.visit_docinfo_item(node, 'copyright')
+
+ def depart_copyright(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_danger(self, node):
+ self.visit_admonition(node, 'danger')
+
+ def depart_danger(self, node):
+ self.depart_admonition()
+
+ def visit_date(self, node):
+ self.visit_docinfo_item(node, 'date')
+
+ def depart_date(self, node):
+ self.depart_docinfo_item(node)
+
+# def visit_decoration(self, node):
+# pass
+
+# def depart_decoration(self, node):
+# pass
+
+ def visit_definition(self, node):
+ self.body.append('%[visit_definition]\n')
+
+ def depart_definition(self, node):
+ self.body.append('\n')
+ self.body.append('%[depart_definition]\n')
+
+ def visit_definition_list(self, node):
+ self.body.append( '\\begin{description}\n' )
+
+ def depart_definition_list(self, node):
+ self.body.append( '\\end{description}\n' )
+
+ def visit_definition_list_item(self, node):
+ self.body.append('%[visit_definition_list_item]\n')
+
+ def depart_definition_list_item(self, node):
+ self.body.append('%[depart_definition_list_item]\n')
+
+ def visit_description(self, node):
+ if self.use_optionlist_for_option_list:
+ self.body.append( ' ' )
+ else:
+ self.body.append( ' & ' )
+
+ def depart_description(self, node):
+ pass
+
+ def visit_docinfo(self, node):
+ self.docinfo = []
+ self.docinfo.append('%' + '_'*75 + '\n')
+ self.docinfo.append('\\begin{center}\n')
+#ACM self.docinfo.append('\\begin{tabularx}{\\admwidth}{lX}\n')
+ self.docinfo.append('\\begin{tabular}\n')
+
+ def depart_docinfo(self, node):
+#ACM self.docinfo.append('\\end{tabularx}\n')
+ self.docinfo.append('\\end{tabular}\n')
+ self.docinfo.append('\\end{center}\n')
+ self.body = self.docinfo + self.body
+ # clear docinfo, so field names are no longer appended.
+ self.docinfo = None
+ if self.use_latex_toc:
+ self.body.append('\\tableofcontents\n\n\\bigskip\n')
+
+ def visit_docinfo_item(self, node, name):
+ # should we stick to latex or docutils.
+ # latex article has its own handling of date and author.
+ # If we use it we get latexs language handling.
+ latex_docinfo = 0
+
+ if name == 'abstract':
+ # NOTE tableofcontents before or after ?
+ # eg after: depart_docinfo
+ # NOTE this limits abstract to text.
+ self.body.append('\\begin{abstract}\n')
+ self.context.append('\\end{abstract}\n')
+ self.context.append(self.body)
+ self.context.append(len(self.body))
+ else:
+ self.docinfo.append('\\textbf{%s}: &\n\t' %
self.language_label(name))
+ if name == 'author':
+#ACM if not self.pdfinfo == None:
+#ACM if not self.pdfauthor:
+#ACM self.pdfauthor = self.attval(node.astext())
+#ACM else:
+#ACM self.pdfauthor += self.author_separator +
self.attval(node.astext())
+ if latex_docinfo:
+ self.head.append('\\author{%s}\n' %
self.attval(node.astext()))
+ raise nodes.SkipNode
+ else:
+ # avoid latexs maketitle generating one for us.
+ self.head.append('\\author{}\n')
+ elif name == 'date':
+ if latex_docinfo:
+ self.head.append('\\date{%s}\n' %
self.attval(node.astext()))
+ raise nodes.SkipNode
+ else:
+ # avoid latexs maketitle generating one for us.
+ self.head.append("\\date{}\n")
+ if name == 'address':
+ self.insert_newline = 1
+ self.docinfo.append('{\\raggedright\n')
+ self.context.append(' } \\\\\n')
+ else:
+ self.context.append(' \\\\\n')
+ self.context.append(self.docinfo)
+ self.context.append(len(self.body))
+ # \thanks is a footnote to the title.
+
+ def depart_docinfo_item(self, node):
+ size = self.context.pop()
+ dest = self.context.pop()
+ tail = self.context.pop()
+ tail = self.body[size:] + [tail]
+ del self.body[size:]
+ dest.extend(tail)
+ # for address we did set insert_newline
+ self.insert_newline = 0
+
+ def visit_doctest_block(self, node):
+ self.body.append( '\\begin{verbatim}' )
+
+ def depart_doctest_block(self, node):
+ self.body.append( '\\end{verbatim}\n' )
+
+ def visit_document(self, node):
+ self.body_prefix.append('\\begin{document}\n')
+#ACM self.body_prefix.append('\\maketitle\n\n')
+ # alternative use titlepage environment.
+ # \begin{titlepage}
+
+ def depart_document(self, node):
+ self.body_suffix.append('\\end{document}\n')
+
+ def visit_emphasis(self, node):
+ self.body.append('\\emph{')
+
+ def depart_emphasis(self, node):
+ self.body.append('}')
+
+ def visit_entry(self, node):
+ # cell separation
+ column_one = 1
+ if self.context[-1] > 0:
+ column_one = 0
+ if not column_one:
+ self.body.append(' & ')
+
+ # multi{row,column}
+ if node.has_key('morerows') and node.has_key('morecols'):
+ raise NotImplementedError('LaTeX can\'t handle cells that'
+ 'span multiple rows *and* columns, sorry.')
+ atts = {}
+ if node.has_key('morerows'):
+ count = node['morerows'] + 1
+ self.body.append('\\multirow{%d}*{' % count)
+ self.context.append('}')
+ elif node.has_key('morecols'):
+ # the vertical bar before column is missing if it is the first
column.
+ # the one after always.
+ if column_one:
+ bar = '|'
+ else:
+ bar = ''
+ count = node['morecols'] + 1
+ self.body.append('\\multicolumn{%d}{%sl|}{' % (count, bar))
+ self.context.append('}')
+ else:
+ self.context.append('')
+
+ # header / not header
+ if isinstance(node.parent.parent, nodes.thead):
+ self.body.append('\\textbf{')
+ self.context.append('}')
+ else:
+ self.context.append('')
+
+ def depart_entry(self, node):
+ self.body.append(self.context.pop()) # header / not header
+ self.body.append(self.context.pop()) # multirow/column
+ self.context[-1] += 1
+
+ def visit_enumerated_list(self, node):
+ # We create our own enumeration list environment.
+ # This allows to set the style and starting value
+ # and unlimited nesting.
+ self._enum_cnt += 1
+
+ enum_style = {'arabic':'arabic',
+ 'loweralpha':'alph',
+ 'upperalpha':'Alph',
+ 'lowerroman':'roman',
+ 'upperroman':'Roman' };
+ enumtype = "arabic"
+ if node.has_key('enumtype'):
+ enumtype = node['enumtype']
+ if enum_style.has_key(enumtype):
+ enumtype = enum_style[enumtype]
+ counter_name = "listcnt%d" % self._enum_cnt;
+ self.body.append('\\newcounter{%s}\n' % counter_name)
+ self.body.append('\\begin{list}{\\%s{%s}}\n' % (enumtype,counter_name))
+ self.body.append('{\n')
+ self.body.append('\\usecounter{%s}\n' % counter_name)
+ # set start after usecounter, because it initializes to zero.
+ if node.has_key('start'):
+ self.body.append('\\addtocounter{%s}{%d}\n' \
+ % (counter_name,node['start']-1))
+ ## set rightmargin equal to leftmargin
+ self.body.append('\\setlength{\\rightmargin}{\\leftmargin}\n')
+ self.body.append('}\n')
+
+ def depart_enumerated_list(self, node):
+ self.body.append('\\end{list}\n')
+
+ def visit_error(self, node):
+ self.visit_admonition(node, 'error')
+
+ def depart_error(self, node):
+ self.depart_admonition()
+
+ def visit_field(self, node):
+ # real output is done in siblings: _argument, _body, _name
+ pass
+
+ def depart_field(self, node):
+ self.body.append('\n')
+ ##self.body.append('%[depart_field]\n')
+
+ def visit_field_argument(self, node):
+ self.body.append('%[visit_field_argument]\n')
+
+ def depart_field_argument(self, node):
+ self.body.append('%[depart_field_argument]\n')
+
+ def visit_field_body(self, node):
+ # BUG by attach as text we loose references.
+ if self.docinfo:
+ self.docinfo.append('%s \\\\\n' % node.astext())
+ raise nodes.SkipNode
+ # what happens if not docinfo
+
+ def depart_field_body(self, node):
+ self.body.append( '\n' )
+
+ def visit_field_list(self, node):
+ if not self.docinfo:
+ self.body.append('\\begin{quote}\n')
+ self.body.append('\\begin{description}\n')
+
+ def depart_field_list(self, node):
+ if not self.docinfo:
+ self.body.append('\\end{description}\n')
+ self.body.append('\\end{quote}\n')
+
+ def visit_field_name(self, node):
+ # BUG this duplicates docinfo_item
+#ACM if self.docinfo:
+#ACM self.docinfo.append('\\textbf{%s}: &\n\t' % node.astext())
+#ACM raise nodes.SkipNode
+#ACM else:
+#ACM self.body.append('\\item [')
+ self.body.append('\\item [')
+
+ def depart_field_name(self, node):
+ if not self.docinfo:
+ self.body.append(':]')
+
+ def visit_figure(self, node):
+ self.body.append( '\\begin{figure}\n' )
+
+ def depart_figure(self, node):
+ self.body.append( '\\end{figure}\n' )
+
+ def visit_footer(self, node):
+ self.context.append(len(self.body))
+
+ def depart_footer(self, node):
+ start = self.context.pop()
+ footer = (['\n\\begin{center}\small\n']
+ + self.body[start:] + ['\n\\end{center}\n'])
+ self.body_suffix[:0] = footer
+ del self.body[start:]
+
+ def visit_footnote(self, node):
+ notename = node['id']
+ self.body.append('\\begin{figure}[b]')
+#ACM self.body.append('\\hypertarget{%s}' % notename)
+
+ def depart_footnote(self, node):
+ self.body.append('\\end{figure}\n')
+
+ def visit_footnote_reference(self, node):
+ href = ''
+ if node.has_key('refid'):
+ href = node['refid']
+ elif node.has_key('refname'):
+ href = self.document.nameids[node['refname']]
+ format = self.settings.footnote_references
+ if format == 'brackets':
+ suffix = '['
+ self.context.append(']')
+ elif format == 'superscript':
+ suffix = '\\raisebox{.5em}[0em]{\\scriptsize'
+ self.context.append('}')
+ else: # shouldn't happen
+ raise AssertionError('Illegal footnote reference format.')
+#ACM self.body.append('%s\\hyperlink{%s}{' % (suffix,href))
+
+ def depart_footnote_reference(self, node):
+ pass
+#ACM self.body.append('}%s' % self.context.pop())
+
+ def visit_generated(self, node):
+ pass
+
+ def depart_generated(self, node):
+ pass
+
+ def visit_header(self, node):
+ self.context.append(len(self.body))
+
+ def depart_header(self, node):
+ start = self.context.pop()
+ self.body_prefix.append('\n\\verb|begin_header|\n')
+ self.body_prefix.extend(self.body[start:])
+ self.body_prefix.append('\n\\verb|end_header|\n')
+ del self.body[start:]
+
+ def visit_hint(self, node):
+ self.visit_admonition(node, 'hint')
+
+ def depart_hint(self, node):
+ self.depart_admonition()
+
+ def visit_image(self, node):
+ atts = node.attributes.copy()
+ href = atts['uri']
+ ##self.body.append('\\begin{center}\n')
+ self.body.append('\\includegraphics{%s}\n' % href)
+ ##self.body.append('\\end{center}\n')
+
+ def depart_image(self, node):
+ pass
+
+ def visit_important(self, node):
+ self.visit_admonition(node, 'important')
+
+ def depart_important(self, node):
+ self.depart_admonition()
+
+ def visit_interpreted(self, node):
+ # @@@ Incomplete, pending a proper implementation on the
+ # Parser/Reader end.
+ self.visit_literal(node)
+
+ def depart_interpreted(self, node):
+ self.depart_literal(node)
+
+ def visit_label(self, node):
+ # footnote/citation label
+ self.body.append('[')
+
+ def depart_label(self, node):
+ self.body.append(']')
+
+ def visit_legend(self, node):
+ self.body.append('{\\small ')
+
+ def depart_legend(self, node):
+ self.body.append('}')
+
+ def visit_line_block(self, node):
+ """line-block:
+ * whitespace (including linebreaks) is significant
+ * inline markup is supported.
+ * serif typeface"""
+ self.mbox_newline = 1
+ self.body.append('\\begin{flushleft}\n\\mbox{')
+
+ def depart_line_block(self, node):
+ self.body.append('}\n\\end{flushleft}\n')
+ self.mbox_newline = 0
+
+ def visit_list_item(self, node):
+ self.body.append('\\item ')
+
+ def depart_list_item(self, node):
+ self.body.append('\n')
+
+ def visit_literal(self, node):
+ self.body.append('\\texttt{')
+
+ def depart_literal(self, node):
+ self.body.append('}')
+
+ def visit_literal_block(self, node):
+ self.use_verbatim_for_literal = 1
+ if (self.use_verbatim_for_literal):
+ self.verbatim = 1
+ self.body.append('\\begin{quote}\n')
+ self.body.append('\\begin{verbatim}\n')
+ else:
+ self.body.append('{\\obeylines\\obeyspaces\\ttfamily\n')
+
+ def depart_literal_block(self, node):
+ if self.use_verbatim_for_literal:
+ self.body.append('\n\\end{verbatim}\n')
+ self.body.append('\\end{quote}\n')
+ self.verbatim = 0
+ else:
+ self.body.append('}\n')
+
+ def visit_meta(self, node):
+ self.body.append('[visit_meta]\n')
+ # BUG maybe set keywords for pdf
+ ##self.head.append(self.starttag(node, 'meta', **node.attributes))
+
+ def depart_meta(self, node):
+ self.body.append('[depart_meta]\n')
+
+ def visit_note(self, node):
+ self.visit_admonition(node, 'note')
+
+ def depart_note(self, node):
+ self.depart_admonition()
+
+ def visit_option(self, node):
+ if self.context[-1]:
+ # this is not the first option
+ self.body.append(', ')
+
+ def depart_option(self, node):
+ # flag tha the first option is done.
+ self.context[-1] += 1
+
+ def visit_option_argument(self, node):
+ """The delimiter betweeen an option and its argument."""
+ self.body.append(node.get('delimiter', ' '))
+
+ def depart_option_argument(self, node):
+ pass
+
+ def visit_option_group(self, node):
+ if self.use_optionlist_for_option_list:
+ self.body.append('\\item [')
+ else:
+ atts = {}
+ if len(node.astext()) > 14:
+ self.body.append('\\multicolumn{2}{l}{')
+ self.context.append('} \\\\\n ')
+ else:
+ self.context.append('')
+ self.body.append('\\texttt{')
+ # flag for first option
+ self.context.append(0)
+
+ def depart_option_group(self, node):
+ self.context.pop() # the flag
+ if self.use_optionlist_for_option_list:
+ self.body.append('] ')
+ else:
+ self.body.append('}')
+ self.body.append(self.context.pop())
+
+ def visit_option_list(self, node):
+ self.body.append('% [option list]\n')
+ if self.use_optionlist_for_option_list:
+ self.body.append('\\begin{optionlist}{3cm}\n')
+ else:
+ self.body.append('\\begin{center}\n')
+ # BUG: use admwidth or make it relative to textwidth ?
+#ACM self.body.append('\\begin{tabularx}{.9\\linewidth}{lX}\n')
+ self.body.append('\\begin{tabular}\n')
+
+ def depart_option_list(self, node):
+ if self.use_optionlist_for_option_list:
+ self.body.append('\\end{optionlist}\n')
+ else:
+ self.body.append('\\end{tabular}\n')
+ self.body.append('\\end{center}\n')
+#ACM self.body.append('\\end{tabularx}\n')
+
+ def visit_option_list_item(self, node):
+ pass
+
+ def depart_option_list_item(self, node):
+ if not self.use_optionlist_for_option_list:
+ self.body.append('\\\\\n')
+
+ def visit_option_string(self, node):
+ ##self.body.append(self.starttag(node, 'span', '', CLASS='option'))
+ pass
+
+ def depart_option_string(self, node):
+ ##self.body.append('</span>')
+ pass
+
+ def visit_organization(self, node):
+ self.visit_docinfo_item(node, 'organization')
+
+ def depart_organization(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_paragraph(self, node):
+ if not self.topic_class == 'contents':
+ self.body.append('\n')
+
+ def depart_paragraph(self, node):
+ if self.topic_class == 'contents':
+ self.body.append('\n')
+ else:
+ self.body.append('\n')
+
+ def visit_problematic(self, node):
+ self.body.append('{\\color{red}\\bfseries{}')
+
+ def depart_problematic(self, node):
+ self.body.append('}')
+
+ def visit_raw(self, node):
+ if node.has_key('format') and node['format'].lower() == 'latex':
+ self.body.append(node.astext())
+ raise nodes.SkipNode
+
+ def visit_reference(self, node):
+ pass
+ # for pdflatex hyperrefs might be supported
+#ACM if node.has_key('refuri'):
+#ACM href = node['refuri']
+#ACM elif node.has_key('refid'):
+#ACM href = '#' + node['refid']
+#ACM elif node.has_key('refname'):
+#ACM href = '#' + self.document.nameids[node['refname']]
+ ##self.body.append('[visit_reference]')
+#ACM self.body.append('\\href{%s}{' % href)
+
+ def depart_reference(self, node):
+ pass
+#ACM self.body.append('}')
+ ##self.body.append('[depart_reference]')
+
+ def visit_revision(self, node):
+ self.visit_docinfo_item(node, 'revision')
+
+ def depart_revision(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_row(self, node):
+ self.context.append(0)
+
+ def depart_row(self, node):
+ self.context.pop() # remove cell counter
+ self.body.append(' \\\\ \\hline\n')
+
+ def visit_section(self, node):
+ self.section_level += 1
+
+ def depart_section(self, node):
+ self.section_level -= 1
+
+ def visit_status(self, node):
+ self.visit_docinfo_item(node, 'status')
+
+ def depart_status(self, node):
+ self.depart_docinfo_item(node)
+
+ def visit_strong(self, node):
+ self.body.append('\\textbf{')
+
+ def depart_strong(self, node):
+ self.body.append('}')
+
+ def visit_substitution_definition(self, node):
+ raise nodes.SkipNode
+
+ def visit_substitution_reference(self, node):
+ self.unimplemented_visit(node)
+
+ def visit_subtitle(self, node):
+ self.title = self.title + \
+ '\\\\\n\\large{%s}\n' % self.encode(node.astext())
+ raise nodes.SkipNode
+
+ def depart_subtitle(self, node):
+ pass
+
+ def visit_system_message(self, node):
+ if node['level'] < self.document.reporter['writer'].report_level:
+ raise nodes.SkipNode
+
+
+ def depart_system_message(self, node):
+ self.body.append('\n')
+
+ def get_colspecs(self):
+ """
+ Return column specification for longtable.
+
+ The width is scaled down by 93%. We do it here
+ because the we can use linewidth which should be the local
+ width.
+ """
+ width = 0
+ for node in self.colspecs:
+ width += node['colwidth']
+ s = ""
+ for node in self.colspecs:
+ colwidth = 0.93 * float(node['colwidth']) / width
+ s += "|p{%.2f\\linewidth}" % colwidth
+ self.colspecs = []
+ return s+"|"
+
+ def visit_table(self, node):
+ if self.use_longtable:
+ self.body.append('\n\\begin{longtable}[c]')
+ else:
+#ACM self.body.append('\n\\begin{tabularx}{\\linewidth}')
+ self.body.append('\n\\begin{tabular}{\\linewidth}')
+ self.context.append('table_sentinel') # sentinel
+ self.context.append(0) # column counter
+
+ def depart_table(self, node):
+ if self.use_longtable:
+ self.body.append('\\end{longtable}\n')
+ else:
+#ACM self.body.append('\\end{tabularx}\n')
+ self.body.append('\\end{tabular}\n')
+ sentinel = self.context.pop()
+ if sentinel != 'table_sentinel':
+ print 'context:', self.context + [sentinel]
+ raise AssertionError
+
+ def table_preamble(self):
+ if self.use_longtable:
+ self.body.append('{%s}\n' % self.get_colspecs())
+ else:
+ if self.context[-1] != 'table_sentinel':
+ self.body.append('{%s}' % ('|X' * self.context.pop() + '|'))
+ self.body.append('\n\\hline')
+
+ def visit_target(self, node):
+ if not (node.has_key('refuri') or node.has_key('refid')
+ or node.has_key('refname')):
+ pass
+#ACM self.body.append('\\hypertarget{%s}{' % node['name'])
+#ACM self.context.append('}')
+ else:
+ self.context.append('')
+
+ def depart_target(self, node):
+ self.body.append(self.context.pop())
+
+ def visit_tbody(self, node):
+ # BUG write preamble if not yet done (colspecs not [])
+ # for tables without heads.
+ if len(self.colspecs) > 0:
+ self.visit_thead(None)
+ self.depart_thead(None)
+ self.body.append('%[visit_tbody]\n')
+
+ def depart_tbody(self, node):
+ self.body.append('%[depart_tbody]\n')
+
+ def visit_term(self, node):
+ self.body.append('\\item[')
+
+ def depart_term(self, node):
+ # definition list term.
+ self.body.append(':]\n')
+
+ def visit_tgroup(self, node):
+ #self.body.append(self.starttag(node, 'colgroup'))
+ #self.context.append('</colgroup>\n')
+ pass
+
+ def depart_tgroup(self, node):
+ pass
+
+ def visit_thead(self, node):
+ # number_of_columns will be zero after get_colspecs.
+ # BUG ! push onto context for depart to pop it.
+ number_of_columns = len(self.colspecs)
+ self.table_preamble()
+ #BUG longtable needs firstpage and lastfooter too.
+ self.body.append('\\hline\n')
+
+ def depart_thead(self, node):
+ if self.use_longtable:
+ # the table header written should be on every page
+ # => \endhead
+ self.body.append('\\endhead\n')
+ # and the firsthead => \endfirsthead
+ # BUG i want a "continued from previous page" on every not
+ # firsthead, but then we need the header twice.
+ #
+ # there is a \endfoot and \endlastfoot too.
+ # but we need the number of columns to
+ # self.body.append('\\multicolumn{%d}{c}{"..."}\n' %
number_of_columns)
+ # self.body.append('\\hline\n\\endfoot\n')
+ # self.body.append('\\hline\n')
+ # self.body.append('\\endlastfoot\n')
+
+
+ def visit_tip(self, node):
+ self.visit_admonition(node, 'tip')
+
+ def depart_tip(self, node):
+ self.depart_admonition()
+
+ def visit_title(self, node):
+ """Only 3 section levels are supported by LaTeX article (AFAIR)."""
+ if isinstance(node.parent, nodes.topic):
+ # section titles before the table of contents.
+#ACM if node.parent.hasattr('id'):
+#ACM self.body.append('\\hypertarget{%s}{}' % node.parent['id'])
+ self.body.append('\\begin{center}\n')
+ self.context.append('\\end{center}\n')
+ ## should this be section subsection or
+#ACM self.body.append('\\subsection*{')
+ self.body.append('\\subsection{')
+ self.context.append('}\n')
+ elif self.section_level == 0:
+ # document title
+ self.title = self.encode(node.astext())
+#ACM if not self.pdfinfo == None:
+#ACM self.pdfinfo.append( 'pdftitle={%s}' %
self.encode(node.astext()) )
+ raise nodes.SkipNode
+ else:
+ self.body.append('\n\n')
+ self.body.append('%' + '_' * 75)
+ self.body.append('\n\n')
+#ACM if node.parent.hasattr('id'):
+#ACM self.body.append('\\hypertarget{%s}{}\n' %
node.parent['id'])
+ # section_level 0 is title and handled above.
+ # BUG: latex has no deeper sections (actually paragrah is no
section either).
+#ACME if self.use_latex_toc:
+ section_star = ""
+#ACM else:
+#ACM section_star = "*"
+ if (self.section_level<=3): # 1,2,3
+ self.body.append('\\%ssection%s{' %
('sub'*(self.section_level-1),section_star))
+ elif (self.section_level==4):
+ #self.body.append('\\paragraph*{')
+ self.body.append('\\subsubsection%s{' % (section_star))
+ else:
+ #self.body.append('\\subparagraph*{')
+ self.body.append('\\subsubsection%s{' % (section_star))
+ # BUG: self.body.append( '\\label{%s}\n' % name)
+ self.context.append('}\n')
+
+ def depart_title(self, node):
+ self.body.append(self.context.pop())
+ if isinstance(node.parent, nodes.topic):
+ self.body.append(self.context.pop())
+ # BUG level depends on style.
+ if node.parent.hasattr('id') and not self.use_latex_toc:
+ # pdflatex allows level 0 to 3
+ # ToC would be the only on level 0 so i choose to decrement the
rest.
+ # "Table of contents" bookmark to see the ToC. To avoid this
+ # we set all zeroes to one.
+ l = self.section_level
+ if l>0:
+ l = l-1
+#ACM self.body.append('\\pdfbookmark[%d]{%s}{%s}\n' % \
+#ACM (l,node.astext(),node.parent['id']))
+
+ def visit_topic(self, node):
+ self.topic_class = node.get('class')
+ if self.use_latex_toc:
+ self.topic_class = ''
+ raise nodes.SkipNode
+
+ def depart_topic(self, node):
+ self.topic_class = ''
+ self.body.append('\n')
+
+ def visit_transition(self, node):
+ self.body.append('\n\n')
+ self.body.append('%' + '_' * 75)
+ self.body.append('\n\\hspace*{\\fill}\\hrulefill\\hspace*{\\fill}')
+ self.body.append('\n\n')
+
+ def depart_transition(self, node):
+ #self.body.append('[depart_transition]')
+ pass
+
+ def visit_version(self, node):
+ self.visit_docinfo_item(node, 'version')
-import locale
-try:
- locale.setlocale(locale.LC_ALL, '')
-except:
- pass
+ def depart_version(self, node):
+ self.depart_docinfo_item(node)
-from docutils.core import publish_cmdline, default_description
+ def visit_warning(self, node):
+ self.visit_admonition(node, 'warning')
+ def depart_warning(self, node):
+ self.depart_admonition()
-description = ('Generates (X)HTML documents from standalone reStructuredText '
- 'sources. ' + default_description)
+ def unimplemented_visit(self, node):
+ raise NotImplementedError('visiting unimplemented node type: %s'
+ % node.__class__.__name__)
-publish_cmdline(writer_name='latex', description=description)
+# def unknown_visit(self, node):
+# def default_visit(self, node):
+
+# vim: set ts=4 et ai :