2 LaTeX Beamer document tree Writer.
5 __docformat__
= 'reStructuredText'
7 from docutils
import frontend
, nodes
8 from docutils
.writers
import latex2e
9 from docutils
.readers
import standalone
10 from docutils
.transforms
import references
, Transform
, TransformError
12 class Writer(latex2e
.Writer
):
14 supported
= ('latexbeamer')
15 """Formats this writer supports."""
18 'LaTeX Beamer Specific Options',
19 'The LaTeX "--output-encoding" default is "latin-1:strict".',
20 (('Specify document options. Multiple options can be given, '
21 'separated by commas. Default is no options.',
22 ['--documentoptions'],
24 ('Use LaTeX footnotes. LaTeX supports only numbered footnotes (does it?). '
25 'Default: no, uses figures.',
26 ['--use-latex-footnotes'],
27 {'default': 0, 'action': 'store_true',
28 'validator': frontend
.validate_boolean
}),
29 ('Format for footnote references: one of "superscript" or '
30 '"brackets". Default is "superscript".',
31 ['--footnote-references'],
32 {'choices': ['superscript', 'brackets'], 'default': 'superscript',
33 'metavar': '<format>',
34 'overrides': 'trim_footnote_reference_space'}),
35 ('Use LaTeX citations. '
36 'Default: no, uses figures which might get mixed with images.',
37 ['--use-latex-citations'],
38 {'default': 0, 'action': 'store_true',
39 'validator': frontend
.validate_boolean
}),
40 ('Format for block quote attributions: one of "dash" (em-dash '
41 'prefix), "parentheses"/"parens", or "none". Default is "dash".',
43 {'choices': ['dash', 'parentheses', 'parens', 'none'],
44 'default': 'dash', 'metavar': '<format>'}),
45 ('Specify a stylesheet file. The file will be "input" by latex in '
46 'the document header. Default is no stylesheet (""). '
47 'Overrides --stylesheet-path.',
49 {'default': '', 'metavar': '<file>',
50 'overrides': 'stylesheet_path'}),
51 ('Specify a stylesheet file, relative to the current working '
52 'directory. Overrides --stylesheet.',
53 ['--stylesheet-path'],
54 {'metavar': '<file>', 'overrides': 'stylesheet'}),
55 ('Table of contents by docutils (default) or latex. Latex (writer) '
56 'supports only one ToC per document, but docutils does not write '
59 {'default': 0, 'action': 'store_true',
60 'validator': frontend
.validate_boolean
}),
61 ('Color of any hyperlinks embedded in text '
62 '(default: "0" (disabled)).',
63 ['--hyperlink-color'], {'default': '0'}),
64 ('Enable compound enumerators for nested enumerated lists '
65 '(e.g. "1.2.a.ii"). Default: disabled.',
66 ['--compound-enumerators'],
67 {'default': None, 'action': 'store_true',
68 'validator': frontend
.validate_boolean
}),
69 ('Disable compound enumerators for nested enumerated lists. This is '
71 ['--no-compound-enumerators'],
72 {'action': 'store_false', 'dest': 'compound_enumerators'}),
73 ('Enable section ("." subsection ...) prefixes for compound '
74 'enumerators. This has no effect without --compound-enumerators. '
76 ['--section-prefix-for-enumerators'],
77 {'default': None, 'action': 'store_true',
78 'validator': frontend
.validate_boolean
}),
79 ('Disable section prefixes for compound enumerators. '
80 'This is the default.',
81 ['--no-section-prefix-for-enumerators'],
82 {'action': 'store_false', 'dest': 'section_prefix_for_enumerators'}),
83 ('Set the separator between section number and enumerator '
84 'for compound enumerated lists. Default is "-".',
85 ['--section-enumerator-separator'],
86 {'default': '-', 'metavar': '<char>'}),
87 ('When possibile, use verbatim for literal-blocks. '
88 'Default is to always use the mbox environment.',
89 ['--use-verbatim-when-possible'],
90 {'default': 0, 'action': 'store_true',
91 'validator': frontend
.validate_boolean
}),
92 ('Table style. "standard" with horizontal and vertical lines, '
93 '"booktabs" (LaTeX booktabs style) only horizontal lines '
94 'above and below the table and below the header or "nolines". '
95 'Default: "standard"',
97 {'choices': ['standard', 'booktabs','nolines'], 'default': 'standard',
98 'metavar': '<format>'}),
99 ('LaTeX graphicx package option. '
100 'Possible values are "dvips", "pdftex". "auto" includes LaTeX code '
101 'to use "pdftex" if processing with pdf(la)tex and dvips otherwise. '
102 'Default is no option.',
103 ['--graphicx-option'],
105 ('LaTeX font encoding. '
106 'Possible values are "T1", "OT1", "" or some other fontenc option. '
107 'The font encoding influences available symbols, e.g. "<<" as one '
108 'character. Default is "" which leads to package "ae" (a T1 '
109 'emulation using CM fonts).',
112 # TODO Themes must be changeable by ``usecolortheme``,
113 # ``usefonttheme``, ``useinnertheme``, and ``useoutertheme``
115 ('LaTeX Beamer theme to use. '
116 'Default is JuanLesPins.',
118 {'default': 'JuanLesPins'}),
119 ('Insert intermediate outline slides at a certain level. '
120 'Possible values are "section" and "subsection". '
121 'Default is no intermediate outline slides.',
122 ['--intermediate-outlines'],
123 {'choices': ['section', 'subsection',],
125 # TODO Some themes accept options which must be supported here as
126 # plain strings for those who know what they do
130 latex2e
.Writer
.__init
__(self
)
131 self
.translator_class
= BeamerTranslator
133 class DocumentClass(latex2e
.DocumentClass
):
134 """Details of a LaTeX document class."""
139 def section(self
, level
):
140 """ Return the section name at the given level for the specific
143 Level is 1,2,3..., as level 0 is the title."""
145 # TODO Level where sections become frames must be an option - might be
146 # determined by a preprocessor, then it is also not fixed - might be
147 # driven by the first content under a section
148 sections
= [ 'section', "begin{frame}\n\\frametitle", ]
149 if level
<= len(sections
):
150 return sections
[level
-1]
154 def section_end(self
, level
):
155 """ Return the section name at the given level for the specific
158 Level is 1,2,3..., as level 0 is the title."""
161 sections
= [ '', "\n\\end{frame}\n", ]
162 if level
<= len(sections
):
163 return sections
[level
-1]
167 class BeamerTranslator(latex2e
.LaTeXTranslator
):
169 def __init__(self
, document
):
170 document
.settings
.documentclass
= 'beamer'
171 document
.settings
.use_latex_docinfo
= 1
172 latex2e
.LaTeXTranslator
.__init
__(self
, document
)
173 # TODO Should be done via explicit head_prefix
174 self
.head_prefix
= [ line
175 for line
in self
.head_prefix
176 if 'typearea' not in line
and 'hyperref' not in line
]
177 # Montpellier, Warsaw, JuanLesPins, Darmstadt, Antibes
178 self
.head_prefix
.extend(('\n',
179 '\\mode<presentation>\n',
182 % ( document
.settings
.beamer_theme
, ),
183 # TODO Argument to `setbeamercovered` must be
185 ' \\setbeamercovered{transparent}\n',
189 # TODO Name of outline slides should be the name given for the contents
190 # (is a `title` element) - might be determined by a preprocessor
191 document
.settings
.toc_title
= 'Outline'
192 # TODO Must be present only if there is a toc
193 if document
.settings
.intermediate_outlines
:
194 if document
.settings
.intermediate_outlines
== 'section':
195 at_begin
= 'AtBeginSection'
196 toc_option
= 'currentsection'
198 at_begin
= 'AtBeginSubsection'
199 toc_option
= 'currentsection,currentsubsection'
200 self
.head_prefix
.extend(('\n',
201 '\\%s[]\n' % ( at_begin
, ),
203 ' \\begin{frame}<beamer>\n',
204 ' \\frametitle{%s}\n' % ( document
.settings
.toc_title
, ),
205 ' \\tableofcontents[%s]\n' % ( toc_option
, ),
209 self
.d_class
= DocumentClass()
212 def visit_docinfo(self
, node
):
214 # TODO :Organization: should be handled as institute
216 def depart_docinfo(self
, node
):
218 # Do not output this because relevant data has been gathered
220 def visit_topic(self
, node
):
221 self
.topic_classes
= node
['classes']
222 if 'contents' in node
['classes']:
223 self
.body
.append( '\n\\begin{frame}\n \\frametitle{%s}\n \\tableofcontents\n\\end{frame}'
224 % ( self
.document
.settings
.toc_title
, ))
225 self
.topic_classes
= []
228 def depart_topic(self
, node
):
229 self
.topic_classes
= []
230 self
.body
.append('\n')
232 def visit_title(self
, node
):
233 """Section and other titles."""
235 if (isinstance(node
.parent
, nodes
.topic
)
236 or isinstance(node
.parent
, nodes
.sidebar
)
237 or isinstance(node
.parent
, nodes
.admonition
)
238 or isinstance(node
.parent
, nodes
.table
)
239 or self
.section_level
== 0):
240 latex2e
.LaTeXTranslator
.visit_title(self
, node
)
242 self
.body
.append('\n\n')
243 self
.body
.append('%' + '_' * 75)
244 self
.body
.append('\n\n')
247 section_name
= self
.d_class
.section(self
.section_level
)
248 self
.body
.append('\\%s{' % (section_name
, ))
249 self
.context
.append('}\n')
251 def visit_subtitle(self
, node
):
252 if isinstance(node
.parent
, nodes
.document
):
253 self
.subtitle
= self
.encode(node
.astext())
256 latex2e
.LaTeXTranslator
.visit_subtitle(self
, node
)
258 def depart_section(self
, node
):
259 self
.body
.append(self
.d_class
.section_end(self
.section_level
))
260 latex2e
.LaTeXTranslator
.depart_section(self
, node
)
263 if self
.pdfinfo
is not None:
265 self
.pdfinfo
.append('pdfauthor={%s}' % self
.pdfauthor
)
267 pdfinfo
= '\\hypersetup{\n' + ',\n'.join(self
.pdfinfo
) + '\n}\n'
270 head
= '\\title{%s}\n\\subtitle{%s}\n\\author{%s}\n\\date{%s}\n' % \
271 (self
.title
, self
.subtitle
,
272 ' \\and\n'.join(['~\\\\\n'.join(author_lines
)
273 for author_lines
in self
.author_stack
]),
275 return ''.join(self
.head_prefix
+ [head
] + self
.head
+ [pdfinfo
]
276 + self
.body_prefix
+ self
.body
+ self
.body_suffix
)
278 # Use an own reader to modify transformations done.
279 class Reader(standalone
.Reader
):
281 def get_transforms(self
):
282 default
= standalone
.Reader
.get_transforms(self
)
285 if i
is not references
.DanglingReferences
]
286 + [ RemoveClassHandout
, ])
288 # TODO Must be supported by the right beamer mode (see section 20.2)
289 class RemoveClassHandout(Transform
):
292 Remove all elements with a given class attribute.
295 # TODO This should be more generic
296 classToRemove
= 'handout'
299 # docutils.transforms.misc.ClassAttribute.default_priority
300 default_priority
= 120
303 for node
in self
.document
.traverse(nodes
.Element
):
304 if node
.has_key('classes'):
305 if self
.classToRemove
in node
['classes']:
307 node
.parent
.remove(node
)
309 # TODO \pause needs to be supported as an inline element; the following works
316 # It also is problematic because it ends up in an error if ``raw`` is disabled
317 # - even when rendering HTML
319 # S5 solves this problem purely by classes and ::
321 # .. role:: incremental
322 # .. default-role:: incremental
324 # in s5defs.txt. Semantics seems to be a \pause before the marked up text.
325 # Unfortunately then the role is used and things like `*emphasis*` don't work.
327 # If there would be a class ``pause`` implemented by `latexbeamer` then
328 # something like this could work::
330 # .. |p| class:: pause
332 # Pause |p| as much |p| as you like |p|
334 # and where |p| you like |p|
336 # and use *any* |p| other role flexibly.
338 # However, any element needs to be checked for the respective class then. A
347 # Unfortunately this doesn't work :-( .
349 # TODO *emphasis* must translate to bold text and **strong emphasis** to \alert
351 # TODO \logo picture must be supported as an option
353 # TODO \appendix must be supported as a directive