PageRenderTime 54ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/src/docutils/writers/latex2e/__init__.py

https://bitbucket.org/kiv/appengine-fb
Python | 2636 lines | 2442 code | 78 blank | 116 comment | 69 complexity | af97396db414197feff1883e24f692ba MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. # $Id: __init__.py 6095 2009-08-22 22:01:26Z milde $
  2. # Author: Engelbert Gruber <grubert@users.sourceforge.net>
  3. # Copyright: This module has been placed in the public domain.
  4. """LaTeX2e document tree Writer."""
  5. __docformat__ = 'reStructuredText'
  6. # code contributions from several people included, thanks to all.
  7. # some named: David Abrahams, Julien Letessier, Lele Gaifax, and others.
  8. #
  9. # convention deactivate code by two # i.e. ##.
  10. import sys
  11. import os
  12. import time
  13. import re
  14. import string
  15. from docutils import frontend, nodes, languages, writers, utils, transforms
  16. from docutils.writers.newlatex2e import unicode_map
  17. class Writer(writers.Writer):
  18. supported = ('latex','latex2e')
  19. """Formats this writer supports."""
  20. settings_spec = (
  21. 'LaTeX-Specific Options',
  22. 'The LaTeX "--output-encoding" default is "latin-1:strict".',
  23. (('Specify documentclass. Default is "article".',
  24. ['--documentclass'],
  25. {'default': 'article', }),
  26. ('Specify document options. Multiple options can be given, '
  27. 'separated by commas. Default is "a4paper".',
  28. ['--documentoptions'],
  29. {'default': 'a4paper', }),
  30. ('Use LaTeX footnotes (currently supports only numbered footnotes). '
  31. 'Default: no, uses figures.',
  32. ['--use-latex-footnotes'],
  33. {'default': 0, 'action': 'store_true',
  34. 'validator': frontend.validate_boolean}),
  35. ('Format for footnote references: one of "superscript" or '
  36. '"brackets". Default is "superscript".',
  37. ['--footnote-references'],
  38. {'choices': ['superscript', 'brackets'], 'default': 'superscript',
  39. 'metavar': '<format>',
  40. 'overrides': 'trim_footnote_reference_space'}),
  41. ('Use LaTeX citations. '
  42. 'Default: no, uses figures which might get mixed with images.',
  43. ['--use-latex-citations'],
  44. {'default': 0, 'action': 'store_true',
  45. 'validator': frontend.validate_boolean}),
  46. ('Format for block quote attributions: one of "dash" (em-dash '
  47. 'prefix), "parentheses"/"parens", or "none". Default is "dash".',
  48. ['--attribution'],
  49. {'choices': ['dash', 'parentheses', 'parens', 'none'],
  50. 'default': 'dash', 'metavar': '<format>'}),
  51. ('Specify LaTeX packages/stylesheets. '
  52. ' A style is referenced with \\usepackage if extension is '
  53. '".sty" or omitted and with \\input else. '
  54. ' Overrides previous --stylesheet and --stylesheet-path settings.',
  55. ['--stylesheet'],
  56. {'default': '', 'metavar': '<file>',
  57. 'overrides': 'stylesheet_path'}),
  58. ('Like --stylesheet, but a relative path is converted from relative '
  59. 'to the current working directory to relative to the output file. ',
  60. ['--stylesheet-path'],
  61. {'metavar': '<file>', 'overrides': 'stylesheet'}),
  62. ('Embed the stylesheet in the output LaTeX file. The stylesheet '
  63. 'file must be accessible during processing. '
  64. ' Default: link to stylesheets',
  65. ['--embed-stylesheet'],
  66. {'default': 0, 'action': 'store_true',
  67. 'validator': frontend.validate_boolean}),
  68. ('Link to the stylesheet(s) in the output file. '
  69. ' This is the default (if not changed in a config file).',
  70. ['--link-stylesheet'],
  71. {'dest': 'embed_stylesheet', 'action': 'store_false'}),
  72. ('Table of contents by Docutils (default) or LaTeX. '
  73. '(Docutils does not know of pagenumbers.) ',
  74. ['--use-latex-toc'],
  75. {'default': 0, 'action': 'store_true',
  76. 'validator': frontend.validate_boolean}),
  77. ('Add parts on top of the section hierarchy.',
  78. ['--use-part-section'],
  79. {'default': 0, 'action': 'store_true',
  80. 'validator': frontend.validate_boolean}),
  81. ('Enclose titlepage in LaTeX titlepage environment.',
  82. ['--use-titlepage-env'],
  83. {'default': 0, 'action': 'store_true',
  84. 'validator': frontend.validate_boolean}),
  85. ('Let LaTeX print author and date, do not show it in docutils '
  86. 'document info.',
  87. ['--use-latex-docinfo'],
  88. {'default': 0, 'action': 'store_true',
  89. 'validator': frontend.validate_boolean}),
  90. ("Use LaTeX abstract environment for the document's abstract. "
  91. 'Per default the abstract is an unnumbered section.',
  92. ['--use-latex-abstract'],
  93. {'default': 0, 'action': 'store_true',
  94. 'validator': frontend.validate_boolean}),
  95. ('Color of any hyperlinks embedded in text '
  96. '(default: "blue", "0" to disable).',
  97. ['--hyperlink-color'], {'default': 'blue'}),
  98. ('Enable compound enumerators for nested enumerated lists '
  99. '(e.g. "1.2.a.ii"). Default: disabled.',
  100. ['--compound-enumerators'],
  101. {'default': None, 'action': 'store_true',
  102. 'validator': frontend.validate_boolean}),
  103. ('Disable compound enumerators for nested enumerated lists. '
  104. 'This is the default.',
  105. ['--no-compound-enumerators'],
  106. {'action': 'store_false', 'dest': 'compound_enumerators'}),
  107. ('Enable section ("." subsection ...) prefixes for compound '
  108. 'enumerators. This has no effect without --compound-enumerators.'
  109. 'Default: disabled.',
  110. ['--section-prefix-for-enumerators'],
  111. {'default': None, 'action': 'store_true',
  112. 'validator': frontend.validate_boolean}),
  113. ('Disable section prefixes for compound enumerators. '
  114. 'This is the default.',
  115. ['--no-section-prefix-for-enumerators'],
  116. {'action': 'store_false', 'dest': 'section_prefix_for_enumerators'}),
  117. ('Set the separator between section number and enumerator '
  118. 'for compound enumerated lists. Default is "-".',
  119. ['--section-enumerator-separator'],
  120. {'default': '-', 'metavar': '<char>'}),
  121. ('When possibile, use the specified environment for literal-blocks. '
  122. 'Default is quoting of whitespace and special chars.',
  123. ['--literal-block-env'],
  124. {'default': ''}),
  125. ('When possibile, use verbatim for literal-blocks. '
  126. 'Compatibility alias for "--literal-block-env=verbatim".',
  127. ['--use-verbatim-when-possible'],
  128. {'default': 0, 'action': 'store_true',
  129. 'validator': frontend.validate_boolean}),
  130. ('Table style. "standard" with horizontal and vertical lines, '
  131. '"booktabs" (LaTeX booktabs style) only horizontal lines '
  132. 'above and below the table and below the header or "nolines". '
  133. 'Default: "standard"',
  134. ['--table-style'],
  135. {'choices': ['standard', 'booktabs','nolines'],
  136. 'default': 'standard',
  137. 'metavar': '<format>'}),
  138. ('LaTeX graphicx package option. '
  139. 'Possible values are "dvips", "pdftex". "auto" includes LaTeX code '
  140. 'to use "pdftex" if processing with pdf(la)tex and dvips otherwise. '
  141. 'Default is no option.',
  142. ['--graphicx-option'],
  143. {'default': ''}),
  144. ('LaTeX font encoding. '
  145. 'Possible values are "", "T1", "OT1", "LGR,T1" or any other '
  146. 'combination of options to the `fontenc` package. '
  147. 'Default is "" which does not load `fontenc`.',
  148. ['--font-encoding'],
  149. {'default': ''}),
  150. ('Per default the latex-writer puts the reference title into '
  151. 'hyperreferences. Specify "ref*" or "pageref*" to get the section '
  152. 'number or the page number.',
  153. ['--reference-label'],
  154. {'default': None, }),
  155. ('Specify style and database for bibtex, for example '
  156. '"--use-bibtex=mystyle,mydb1,mydb2".',
  157. ['--use-bibtex'],
  158. {'default': None, }),
  159. ),)
  160. settings_defaults = {'output_encoding': 'latin-1',
  161. 'sectnum_depth': 0 # updated by SectNum transform
  162. }
  163. relative_path_settings = ('stylesheet_path',)
  164. config_section = 'latex2e writer'
  165. config_section_dependencies = ('writers',)
  166. visitor_attributes = ('head_prefix', 'stylesheet', 'head',
  167. 'body_prefix', 'body', 'body_suffix')
  168. output = None
  169. """Final translated form of `document`."""
  170. def __init__(self):
  171. writers.Writer.__init__(self)
  172. self.translator_class = LaTeXTranslator
  173. # Override parent method to add latex-specific transforms
  174. ## def get_transforms(self):
  175. ## # call the parent class' method
  176. ## transforms = writers.Writer.get_transforms(self)
  177. ## # print transforms
  178. ## # TODO: footnote collection transform
  179. ## # transforms.append(footnotes.collect)
  180. ## return transforms
  181. def translate(self):
  182. visitor = self.translator_class(self.document)
  183. self.document.walkabout(visitor)
  184. self.output = visitor.astext()
  185. # copy parts
  186. for attr in self.visitor_attributes:
  187. setattr(self, attr, getattr(visitor, attr))
  188. def assemble_parts(self):
  189. writers.Writer.assemble_parts(self)
  190. for part in self.visitor_attributes:
  191. if part.startswith('body'):
  192. # body contains inline elements, so join without newline
  193. self.parts[part] = ''.join(getattr(self, part))
  194. else:
  195. self.parts[part] = '\n'.join(getattr(self, part))
  196. class Babel(object):
  197. """Language specifics for LaTeX."""
  198. # country code by a.schlock.
  199. # partly manually converted from iso and babel stuff, dialects and some
  200. _ISO639_TO_BABEL = {
  201. 'no': 'norsk', #XXX added by hand ( forget about nynorsk?)
  202. 'gd': 'scottish', #XXX added by hand
  203. 'hu': 'magyar', #XXX added by hand
  204. 'pt': 'portuguese',#XXX added by hand
  205. 'sl': 'slovenian',
  206. 'af': 'afrikaans',
  207. 'bg': 'bulgarian',
  208. 'br': 'breton',
  209. 'ca': 'catalan',
  210. 'cs': 'czech',
  211. 'cy': 'welsh',
  212. 'da': 'danish',
  213. 'fr': 'french',
  214. # french, francais, canadien, acadian
  215. 'de': 'ngerman', #XXX rather than german
  216. # ngerman, naustrian, german, germanb, austrian
  217. 'el': 'greek',
  218. 'en': 'english',
  219. # english, USenglish, american, UKenglish, british, canadian
  220. 'eo': 'esperanto',
  221. 'es': 'spanish',
  222. 'et': 'estonian',
  223. 'eu': 'basque',
  224. 'fi': 'finnish',
  225. 'ga': 'irish',
  226. 'gl': 'galician',
  227. 'he': 'hebrew',
  228. 'hr': 'croatian',
  229. 'hu': 'hungarian',
  230. 'is': 'icelandic',
  231. 'it': 'italian',
  232. 'la': 'latin',
  233. 'nl': 'dutch',
  234. 'pl': 'polish',
  235. 'pt': 'portuguese',
  236. 'ro': 'romanian',
  237. 'ru': 'russian',
  238. 'sk': 'slovak',
  239. 'sr': 'serbian',
  240. 'sv': 'swedish',
  241. 'tr': 'turkish',
  242. 'uk': 'ukrainian'
  243. }
  244. def __init__(self, lang):
  245. self.language = lang
  246. self.quote_index = 0
  247. self.quotes = ('``', "''")
  248. self.setup = '' # language dependent configuration code
  249. # double quotes are "active" in some languages (e.g. German).
  250. # TODO: use \textquotedbl in OT1 font encoding?
  251. self.literal_double_quote = '"'
  252. if self.language.startswith('de'):
  253. self.quotes = ('{\\glqq}', '\\grqq{}')
  254. self.literal_double_quote = '\\dq{}'
  255. if self.language.startswith('it'):
  256. self.literal_double_quote = r'{\char`\"}'
  257. if self.language.startswith('es'):
  258. # reset tilde ~ to the original binding (nobreakspace):
  259. self.setup = ('\n'
  260. r'\addto\shorthandsspanish{\spanishdeactivate{."~<>}}')
  261. def next_quote(self):
  262. q = self.quotes[self.quote_index]
  263. self.quote_index = (self.quote_index+1) % 2
  264. return q
  265. def quote_quotes(self,text):
  266. t = None
  267. for part in text.split('"'):
  268. if t == None:
  269. t = part
  270. else:
  271. t += self.next_quote() + part
  272. return t
  273. def get_language(self):
  274. lang = self.language.split('_')[0] # filter dialects
  275. return self._ISO639_TO_BABEL.get(lang, "")
  276. # Building blocks for the latex preamble
  277. # --------------------------------------
  278. class SortableDict(dict):
  279. """Dictionary with additional sorting methods"""
  280. def sortedkeys(self):
  281. """Return sorted list of keys"""
  282. keys = self.keys()
  283. keys.sort()
  284. return keys
  285. def sortedvalues(self):
  286. """Return list of values sorted by keys"""
  287. return [self[key] for key in self.sortedkeys()]
  288. # PreambleCmds
  289. # `````````````
  290. # A container for LaTeX code snippets that can be
  291. # inserted into the preamble if required in the document.
  292. #
  293. # .. The package 'makecmds' would enable shorter definitions using the
  294. # \providelength and \provideenvironment commands.
  295. # However, it is pretty non-standard (texlive-latex-extra).
  296. class PreambleCmds(object):
  297. """Building blocks for the latex preamble."""
  298. PreambleCmds.abstract = r"""
  299. % abstract title
  300. \providecommand*{\DUtitleabstract}[1]{\centerline{\textbf{#1}}}"""
  301. PreambleCmds.admonition = r"""
  302. % admonition (specially marked topic)
  303. \providecommand{\DUadmonition}[2][class-arg]{%
  304. % try \DUadmonition#1{#2}:
  305. \ifcsname DUadmonition#1\endcsname%
  306. \csname DUadmonition#1\endcsname{#2}%
  307. \else
  308. \begin{center}
  309. \fbox{\parbox{0.9\textwidth}{#2}}
  310. \end{center}
  311. \fi
  312. }"""
  313. ## PreambleCmds.caption = r"""% configure caption layout
  314. ## \usepackage{caption}
  315. ## \captionsetup{singlelinecheck=false}% no exceptions for one-liners"""
  316. PreambleCmds.color = r"""\usepackage{color}"""
  317. PreambleCmds.docinfo = r"""
  318. % docinfo (width of docinfo table)
  319. \DUprovidelength{\DUdocinfowidth}{0.9\textwidth}"""
  320. # PreambleCmds.docinfo._requirements = 'providelength'
  321. PreambleCmds.embedded_package_wrapper = r"""\makeatletter
  322. %% embedded stylesheet: %s
  323. %s
  324. \makeatother"""
  325. PreambleCmds.dedication = r"""
  326. % dedication topic
  327. \providecommand{\DUtopicdedication}[1]{\begin{center}#1\end{center}}"""
  328. PreambleCmds.error = r"""
  329. % error admonition title
  330. \providecommand*{\DUtitleerror}[1]{\DUtitle{\color{red}#1}}"""
  331. # PreambleCmds.errortitle._requirements = 'color'
  332. PreambleCmds.fieldlist = r"""
  333. % fieldlist environment
  334. \ifthenelse{\isundefined{\DUfieldlist}}{
  335. \newenvironment{DUfieldlist}%
  336. {\quote\description}
  337. {\enddescription\endquote}
  338. }{}"""
  339. PreambleCmds.float_settings = r"""\usepackage{float} % float configuration
  340. \floatplacement{figure}{H} % place figures here definitely"""
  341. PreambleCmds.footnote_floats = r"""% settings for footnotes as floats:
  342. \setlength{\floatsep}{0.5em}
  343. \setlength{\textfloatsep}{\fill}
  344. \addtolength{\textfloatsep}{3em}
  345. \renewcommand{\textfraction}{0.5}
  346. \renewcommand{\topfraction}{0.5}
  347. \renewcommand{\bottomfraction}{0.5}
  348. \setcounter{totalnumber}{50}
  349. \setcounter{topnumber}{50}
  350. \setcounter{bottomnumber}{50}"""
  351. PreambleCmds.graphicx_auto = r"""% Check output format
  352. \ifx\pdftexversion\undefined
  353. \usepackage{graphicx}
  354. \else
  355. \usepackage[pdftex]{graphicx}
  356. \fi'))"""
  357. PreambleCmds.inline = r"""
  358. % inline markup (custom roles)
  359. % \DUrole{#1}{#2} tries \DUrole#1{#2}
  360. \providecommand*{\DUrole}[2]{%
  361. \ifcsname DUrole#1\endcsname%
  362. \csname DUrole#1\endcsname{#2}%
  363. \else% backwards compatibility: try \docutilsrole#1{#2}
  364. \ifcsname docutilsrole#1\endcsname%
  365. \csname docutilsrole#1\endcsname{#2}%
  366. \else%
  367. #2%
  368. \fi%
  369. \fi%
  370. }"""
  371. PreambleCmds.legend = r"""
  372. % legend environment
  373. \ifthenelse{\isundefined{\DUlegend}}{
  374. \newenvironment{DUlegend}{\small}{}
  375. }{}"""
  376. PreambleCmds.lineblock = r"""
  377. % lineblock environment
  378. \DUprovidelength{\DUlineblockindent}{2.5em}
  379. \ifthenelse{\isundefined{\DUlineblock}}{
  380. \newenvironment{DUlineblock}[1]{%
  381. \list{}{\setlength{\partopsep}{\parskip}
  382. \addtolength{\partopsep}{\baselineskip}
  383. \setlength{\topsep}{0pt}
  384. \setlength{\itemsep}{0.15\baselineskip}
  385. \setlength{\parsep}{0pt}
  386. \setlength{\leftmargin}{#1}}
  387. \raggedright
  388. }
  389. {\endlist}
  390. }{}"""
  391. # PreambleCmds.lineblock._requirements = 'providelength'
  392. PreambleCmds.linking = r"""
  393. %% hyperref package (PDF hyperlinks):
  394. \ifthenelse{\isundefined{\hypersetup}}{
  395. \usepackage[colorlinks=%s,linkcolor=%s,urlcolor=%s]{hyperref}
  396. }{}"""
  397. PreambleCmds.minitoc = r"""%% local table of contents
  398. \usepackage{minitoc}"""
  399. PreambleCmds.optionlist = r"""
  400. % optionlist environment
  401. \providecommand*{\DUoptionlistlabel}[1]{\bf #1 \hfill}
  402. \DUprovidelength{\DUoptionlistindent}{3cm}
  403. \ifthenelse{\isundefined{\DUoptionlist}}{
  404. \newenvironment{DUoptionlist}{%
  405. \list{}{\setlength{\labelwidth}{\DUoptionlistindent}
  406. \setlength{\rightmargin}{1cm}
  407. \setlength{\leftmargin}{\rightmargin}
  408. \addtolength{\leftmargin}{\labelwidth}
  409. \addtolength{\leftmargin}{\labelsep}
  410. \renewcommand{\makelabel}{\DUoptionlistlabel}}
  411. }
  412. {\endlist}
  413. }{}"""
  414. # PreambleCmds.optionlist._requirements = 'providelength'
  415. PreambleCmds.providelength = r"""
  416. % providelength (provide a length variable and set default, if it is new)
  417. \providecommand*{\DUprovidelength}[2]{
  418. \ifthenelse{\isundefined{#1}}{\newlength{#1}\setlength{#1}{#2}}{}
  419. }"""
  420. PreambleCmds.rubric = r"""
  421. % rubric (informal heading)
  422. \providecommand*{\DUrubric}[2][class-arg]{%
  423. \subsubsection*{\centering\textit{\textmd{#2}}}}"""
  424. PreambleCmds.sidebar = r"""
  425. % sidebar (text outside the main text flow)
  426. \providecommand{\DUsidebar}[2][class-arg]{%
  427. \begin{center}
  428. \colorbox[gray]{0.80}{\parbox{0.9\textwidth}{#2}}
  429. \end{center}
  430. }"""
  431. PreambleCmds.subtitle = r"""
  432. % subtitle (for topic/sidebar)
  433. \providecommand*{\DUsubtitle}[2][class-arg]{\par\emph{#2}\smallskip}"""
  434. PreambleCmds.table = r"""\usepackage{longtable}
  435. \usepackage{array}
  436. \setlength{\extrarowheight}{2pt}
  437. \newlength{\DUtablewidth} % internal use in tables"""
  438. PreambleCmds.documenttitle = r"""
  439. %%%%%% Title metadata
  440. \title{%s}
  441. \author{%s}
  442. \date{%s}"""
  443. PreambleCmds.titlereference = r"""
  444. % titlereference role
  445. \providecommand*{\DUroletitlereference}[1]{\textsl{#1}}"""
  446. PreambleCmds.title = r"""
  447. % title for topics, admonitions and sidebar
  448. \providecommand*{\DUtitle}[2][class-arg]{%
  449. % call \DUtitle#1{#2} if it exists:
  450. \ifcsname DUtitle#1\endcsname%
  451. \csname DUtitle#1\endcsname{#2}%
  452. \else
  453. \smallskip\noindent\textbf{#2}\smallskip%
  454. \fi
  455. }"""
  456. PreambleCmds.topic = r"""
  457. % topic (quote with heading)
  458. \providecommand{\DUtopic}[2][class-arg]{%
  459. \ifcsname DUtopic#1\endcsname%
  460. \csname DUtopic#1\endcsname{#2}%
  461. \else
  462. \begin{quote}#2\end{quote}
  463. \fi
  464. }"""
  465. PreambleCmds.transition = r"""
  466. % transition (break, fancybreak, anonymous section)
  467. \providecommand*{\DUtransition}[1][class-arg]{%
  468. \hspace*{\fill}\hrulefill\hspace*{\fill}
  469. \vskip 0.5\baselineskip
  470. }"""
  471. class DocumentClass(object):
  472. """Details of a LaTeX document class."""
  473. def __init__(self, document_class, with_part=False):
  474. self.document_class = document_class
  475. self._with_part = with_part
  476. self.sections = ['section', 'subsection', 'subsubsection',
  477. 'paragraph', 'subparagraph']
  478. if self.document_class in ('book', 'memoir', 'report',
  479. 'scrbook', 'scrreprt'):
  480. self.sections.insert(0, 'chapter')
  481. if self._with_part:
  482. self.sections.insert(0, 'part')
  483. def section(self, level):
  484. """Return the LaTeX section name for section `level`.
  485. The name depends on the specific document class.
  486. Level is 1,2,3..., as level 0 is the title.
  487. """
  488. if level <= len(self.sections):
  489. return self.sections[level-1]
  490. else:
  491. return self.sections[-1]
  492. class Table(object):
  493. """Manage a table while traversing.
  494. Maybe change to a mixin defining the visit/departs, but then
  495. class Table internal variables are in the Translator.
  496. Table style might be
  497. :standard: horizontal and vertical lines
  498. :booktabs: only horizontal lines (requires "booktabs" LaTeX package)
  499. :nolines: (or borderless) no lines
  500. """
  501. def __init__(self,translator,latex_type,table_style):
  502. self._translator = translator
  503. self._latex_type = latex_type
  504. self._table_style = table_style
  505. self._open = 0
  506. # miscellaneous attributes
  507. self._attrs = {}
  508. self._col_width = []
  509. self._rowspan = []
  510. self.stubs = []
  511. self._in_thead = 0
  512. def open(self):
  513. self._open = 1
  514. self._col_specs = []
  515. self.caption = None
  516. self._attrs = {}
  517. self._in_head = 0 # maybe context with search
  518. def close(self):
  519. self._open = 0
  520. self._col_specs = None
  521. self.caption = None
  522. self._attrs = {}
  523. self.stubs = []
  524. def is_open(self):
  525. return self._open
  526. def set_table_style(self, table_style):
  527. if not table_style in ('standard','booktabs','borderless','nolines'):
  528. return
  529. self._table_style = table_style
  530. def get_latex_type(self):
  531. return self._latex_type
  532. def set(self,attr,value):
  533. self._attrs[attr] = value
  534. def get(self,attr):
  535. if attr in self._attrs:
  536. return self._attrs[attr]
  537. return None
  538. def get_vertical_bar(self):
  539. if self._table_style == 'standard':
  540. return '|'
  541. return ''
  542. # horizontal lines are drawn below a row,
  543. def get_opening(self):
  544. if self._latex_type == 'longtable':
  545. # otherwise longtable might move before paragraph and subparagraph
  546. prefix = '\\leavevmode\n'
  547. else:
  548. prefix = ''
  549. prefix += '\setlength{\DUtablewidth}{\linewidth}'
  550. return '%s\n\\begin{%s}[c]' % (prefix, self._latex_type)
  551. def get_closing(self):
  552. line = ''
  553. if self._table_style == 'booktabs':
  554. line = '\\bottomrule\n'
  555. elif self._table_style == 'standard':
  556. lines = '\\hline\n'
  557. return '%s\\end{%s}' % (line,self._latex_type)
  558. def visit_colspec(self, node):
  559. self._col_specs.append(node)
  560. # "stubs" list is an attribute of the tgroup element:
  561. self.stubs.append(node.attributes.get('stub'))
  562. def get_colspecs(self):
  563. """Return column specification for longtable.
  564. Assumes reST line length being 80 characters.
  565. Table width is hairy.
  566. === ===
  567. ABC DEF
  568. === ===
  569. usually gets to narrow, therefore we add 1 (fiddlefactor).
  570. """
  571. width = 80
  572. total_width = 0.0
  573. # first see if we get too wide.
  574. for node in self._col_specs:
  575. colwidth = float(node['colwidth']+1) / width
  576. total_width += colwidth
  577. self._col_width = []
  578. self._rowspan = []
  579. # donot make it full linewidth
  580. factor = 0.93
  581. if total_width > 1.0:
  582. factor /= total_width
  583. bar = self.get_vertical_bar()
  584. latex_table_spec = ''
  585. for node in self._col_specs:
  586. colwidth = factor * float(node['colwidth']+1) / width
  587. self._col_width.append(colwidth+0.005)
  588. self._rowspan.append(0)
  589. latex_table_spec += '%sp{%.3f\\DUtablewidth}' % (bar, colwidth+0.005)
  590. return latex_table_spec+bar
  591. def get_column_width(self):
  592. """Return columnwidth for current cell (not multicell)."""
  593. return '%.2f\\DUtablewidth' % self._col_width[self._cell_in_row-1]
  594. def get_caption(self):
  595. if not self.caption:
  596. return ''
  597. if 1 == self._translator.thead_depth():
  598. return r'\caption{%s}\\' '\n' % self.caption
  599. return r'\caption[]{%s (... continued)}\\' '\n' % self.caption
  600. def need_recurse(self):
  601. if self._latex_type == 'longtable':
  602. return 1 == self._translator.thead_depth()
  603. return 0
  604. def visit_thead(self):
  605. self._in_thead += 1
  606. if self._table_style == 'standard':
  607. return ['\\hline\n']
  608. elif self._table_style == 'booktabs':
  609. return ['\\toprule\n']
  610. return []
  611. def depart_thead(self):
  612. a = []
  613. #if self._table_style == 'standard':
  614. # a.append('\\hline\n')
  615. if self._table_style == 'booktabs':
  616. a.append('\\midrule\n')
  617. if self._latex_type == 'longtable':
  618. if 1 == self._translator.thead_depth():
  619. a.append('\\endfirsthead\n')
  620. else:
  621. a.append('\\endhead\n')
  622. a.append(r'\multicolumn{%d}{c}' % len(self._col_specs) +
  623. r'{\hfill ... continued on next page} \\')
  624. a.append('\n\\endfoot\n\\endlastfoot\n')
  625. # for longtable one could add firsthead, foot and lastfoot
  626. self._in_thead -= 1
  627. return a
  628. def visit_row(self):
  629. self._cell_in_row = 0
  630. def depart_row(self):
  631. res = [' \\\\\n']
  632. self._cell_in_row = None # remove cell counter
  633. for i in range(len(self._rowspan)):
  634. if (self._rowspan[i]>0):
  635. self._rowspan[i] -= 1
  636. if self._table_style == 'standard':
  637. rowspans = [i+1 for i in range(len(self._rowspan))
  638. if (self._rowspan[i]<=0)]
  639. if len(rowspans)==len(self._rowspan):
  640. res.append('\\hline\n')
  641. else:
  642. cline = ''
  643. rowspans.reverse()
  644. # TODO merge clines
  645. while 1:
  646. try:
  647. c_start = rowspans.pop()
  648. except:
  649. break
  650. cline += '\\cline{%d-%d}\n' % (c_start,c_start)
  651. res.append(cline)
  652. return res
  653. def set_rowspan(self,cell,value):
  654. try:
  655. self._rowspan[cell] = value
  656. except:
  657. pass
  658. def get_rowspan(self,cell):
  659. try:
  660. return self._rowspan[cell]
  661. except:
  662. return 0
  663. def get_entry_number(self):
  664. return self._cell_in_row
  665. def visit_entry(self):
  666. self._cell_in_row += 1
  667. def is_stub_column(self):
  668. if len(self.stubs) >= self._cell_in_row:
  669. return self.stubs[self._cell_in_row-1]
  670. return False
  671. class LaTeXTranslator(nodes.NodeVisitor):
  672. # When options are given to the documentclass, latex will pass them
  673. # to other packages, as done with babel.
  674. # Dummy settings might be taken from document settings
  675. # Templates
  676. # ---------
  677. latex_head = r'\documentclass[%s]{%s}'
  678. linking = PreambleCmds.linking # if false, hyperref is not loaded
  679. # TODO: use a config value?
  680. generator = '% generated by Docutils <http://docutils.sourceforge.net/>'
  681. # Config setting defaults
  682. # -----------------------
  683. # TODO: use mixins for different implementations.
  684. # list environment for docinfo. else tabularx
  685. ## use_optionlist_for_docinfo = False # TODO: NOT YET IN USE
  686. # Use compound enumerations (1.A.1.)
  687. compound_enumerators = 0
  688. # If using compound enumerations, include section information.
  689. section_prefix_for_enumerators = 0
  690. # This is the character that separates the section ("." subsection ...)
  691. # prefix from the regular list enumerator.
  692. section_enumerator_separator = '-'
  693. # default link color
  694. hyperlink_color = 'blue'
  695. # Auxiliary variables
  696. # -------------------
  697. has_latex_toc = False # is there a toc in the doc? (needed by minitoc)
  698. is_toc_list = False # is the current bullet_list a ToC?
  699. section_level = 0
  700. # Flags to encode():
  701. # inside citation reference labels underscores dont need to be escaped
  702. inside_citation_reference_label = False
  703. verbatim = False # do not encode
  704. insert_non_breaking_blanks = False # replace blanks by "~"
  705. insert_newline = False # add latex newline commands
  706. literal = False # teletype: replace underscores
  707. literal_block = False # inside literal block: no quote mangling
  708. def __init__(self, document):
  709. nodes.NodeVisitor.__init__(self, document)
  710. self.settings = settings = document.settings
  711. self.latex_encoding = self.to_latex_encoding(settings.output_encoding)
  712. self.use_latex_toc = settings.use_latex_toc
  713. self.use_latex_docinfo = settings.use_latex_docinfo
  714. self.use_latex_footnotes = settings.use_latex_footnotes
  715. self._use_latex_citations = settings.use_latex_citations
  716. self.embed_stylesheet = settings.embed_stylesheet
  717. self._reference_label = settings.reference_label
  718. self.hyperlink_color = settings.hyperlink_color
  719. self.compound_enumerators = settings.compound_enumerators
  720. self.font_encoding = settings.font_encoding
  721. self.section_prefix_for_enumerators = (
  722. settings.section_prefix_for_enumerators)
  723. self.section_enumerator_separator = (
  724. settings.section_enumerator_separator.replace('_', '\\_'))
  725. if self.hyperlink_color == '0':
  726. self.hyperlink_color = 'black'
  727. self.colorlinks = 'false'
  728. else:
  729. self.colorlinks = 'true'
  730. # literal blocks:
  731. self.literal_block_env = ''
  732. self.literal_block_options = ''
  733. if settings.literal_block_env != '':
  734. (none,
  735. self.literal_block_env,
  736. self.literal_block_options,
  737. none ) = re.split('(\w+)(.*)', settings.literal_block_env)
  738. elif settings.use_verbatim_when_possible:
  739. self.literal_block_env = 'verbatim'
  740. #
  741. if self.settings.use_bibtex:
  742. self.bibtex = self.settings.use_bibtex.split(',',1)
  743. # TODO avoid errors on not declared citations.
  744. else:
  745. self.bibtex = None
  746. # language: labels, bibliographic_fields, and author_separators.
  747. # to allow writing labes for specific languages.
  748. self.language = languages.get_language(settings.language_code)
  749. self.babel = Babel(settings.language_code)
  750. self.author_separator = self.language.author_separators[0]
  751. self.d_options = [self.settings.documentoptions,
  752. self.babel.get_language()]
  753. self.d_options = ','.join([opt for opt in self.d_options if opt])
  754. self.d_class = DocumentClass(settings.documentclass,
  755. settings.use_part_section)
  756. # object for a table while proccessing.
  757. self.table_stack = []
  758. self.active_table = Table(self,'longtable',settings.table_style)
  759. # Two special dictionaries to collect document-specific requirements.
  760. # Values will be inserted
  761. # * in alphabetic order of their keys,
  762. # * only once, even if required multiple times.
  763. self.requirements = SortableDict() # inserted before style sheet
  764. self.fallbacks = SortableDict() # inserted after style sheet
  765. # Page layout with typearea (if there are relevant document options).
  766. if (settings.documentclass.find('scr') == -1 and
  767. (self.d_options.find('DIV') != -1 or
  768. self.d_options.find('BCOR') != -1)):
  769. self.requirements['typearea'] = r'\usepackage{typearea}'
  770. if self.font_encoding == '':
  771. fontenc_header = r'%\usepackage[OT1]{fontenc}'
  772. else:
  773. fontenc_header = r'\usepackage[%s]{fontenc}' % self.font_encoding
  774. if self.settings.graphicx_option == '':
  775. self.graphicx_package = r'\usepackage{graphicx}'
  776. elif self.settings.graphicx_option.lower() == 'auto':
  777. self.graphicx_package = PreambleCmds.graphicx_auto
  778. else:
  779. self.graphicx_package = (r'\usepackage[%s]{graphicx}' %
  780. self.settings.graphicx_option)
  781. # include all supported sections in toc and PDF bookmarks
  782. # (or use documentclass-default (as currently))?
  783. ## if self.use_latex_toc:
  784. ## self.requirements['tocdepth'] = (r'\setcounter{tocdepth}{%d}' %
  785. ## len(self.d_class.sections))
  786. if not self.settings.sectnum_xform: # section numbering by LaTeX:
  787. sectnum_cmds = []
  788. # sectnum_depth:
  789. # 0 no "sectnum" directive -> no section numbers
  790. # None "sectnum" directive without depth arg -> LaTeX default
  791. # else value of the "depth" argument -> limit to supported
  792. # section levels
  793. if settings.sectnum_depth is not None:
  794. sectnum_depth = min(settings.sectnum_depth,
  795. len(self.d_class.sections))
  796. sectnum_cmds.append(r'\setcounter{secnumdepth}{%d}' %
  797. sectnum_depth)
  798. # start with specified number:
  799. if (hasattr(settings, 'sectnum_start') and
  800. settings.sectnum_start != 1):
  801. sectnum_cmds.append(r'\setcounter{%s}{%d}' %
  802. (self.d_class.sections[0],
  803. settings.sectnum_start-1))
  804. # currently ignored (configure in a stylesheet):
  805. ## settings.sectnum_prefix
  806. ## settings.sectnum_suffix
  807. if sectnum_cmds:
  808. self.requirements['sectnum'] = '\n'.join(sectnum_cmds)
  809. # packages and/or stylesheets
  810. # ---------------------------
  811. self.stylesheet = ['\n%%% User specified packages and stylesheets']
  812. # get list of style sheets from settings
  813. styles = utils.get_stylesheet_list(settings)
  814. # adapt path if --stylesheet_path is used
  815. if settings.stylesheet_path and not(self.embed_stylesheet):
  816. styles = [utils.relative_path(settings._destination, sheet)
  817. for sheet in styles]
  818. for sheet in styles:
  819. (base, ext) = os.path.splitext(sheet)
  820. is_package = ext in ['.sty', '']
  821. if self.embed_stylesheet:
  822. if is_package:
  823. sheet = base + '.sty' # adapt package name
  824. # wrap in \makeatletter, \makeatother
  825. wrapper = PreambleCmds.embedded_package_wrapper
  826. else:
  827. wrapper = '%% embedded stylesheet: %s\n%s'
  828. settings.record_dependencies.add(sheet)
  829. self.stylesheet.append(wrapper % (sheet, open(sheet).read()))
  830. else: # link to style sheet
  831. if is_package:
  832. self.stylesheet.append(r'\usepackage{%s}' % base)
  833. else:
  834. self.stylesheet.append(r'\input{%s}' % sheet)
  835. # Part of LaTeX preamble before style sheet(s)
  836. self.head_prefix = [
  837. self.generator,
  838. self.latex_head % (self.d_options,self.settings.documentclass),
  839. ## '%%% Requirements',
  840. # multi-language support (language is in document settings)
  841. '\\usepackage{babel}%s' % self.babel.setup,
  842. fontenc_header,
  843. r'\usepackage[%s]{inputenc}' % self.latex_encoding,
  844. r'\usepackage{ifthen}',
  845. r'\usepackage{fixltx2e} % fix LaTeX2e shortcomings',
  846. ] # custom requirements will be added later
  847. # Part of LaTeX preamble following the stylesheet
  848. self.head = []
  849. if self.linking: # and maybe check for pdf
  850. self.pdfinfo = []
  851. self.pdfauthor = []
  852. # pdftitle, pdfsubject, pdfauthor, pdfkeywords,
  853. # pdfcreator, pdfproducer
  854. else:
  855. self.pdfinfo = None
  856. # Title metadata: Title, Date, and Author(s)
  857. # separate title, so we can append subtitle.
  858. self.title = []
  859. # if use_latex_docinfo: collects lists of
  860. # author/organization/contact/address lines
  861. self.author_stack = []
  862. # an empty string supresses the "auto-date" feature of \maketitle
  863. self.date = ''
  864. self.body_prefix = ['\n%%% Body\n\\begin{document}\n']
  865. self.body = []
  866. self.body_suffix = ['\n\\end{document}\n']
  867. self.context = []
  868. # Stack of section counters so that we don't have to use_latex_toc.
  869. # This will grow and shrink as processing occurs.
  870. # Initialized for potential first-level sections.
  871. self._section_number = [0]
  872. # The current stack of enumerations so that we can expand
  873. # them into a compound enumeration.
  874. self._enumeration_counters = []
  875. # The maximum number of enumeration counters we've used.
  876. # If we go beyond this number, we need to create a new
  877. # counter; otherwise, just reuse an old one.
  878. self._max_enumeration_counters = 0
  879. self._bibitems = []
  880. self.docinfo = []
  881. self.literal_block_stack = []
  882. # Auxiliary Methods
  883. # -----------------
  884. def to_latex_encoding(self,docutils_encoding):
  885. """Translate docutils encoding name into LaTeX's.
  886. Default method is remove "-" and "_" chars from docutils_encoding.
  887. """
  888. tr = { 'iso-8859-1': 'latin1', # west european
  889. 'iso-8859-2': 'latin2', # east european
  890. 'iso-8859-3': 'latin3', # esperanto, maltese
  891. 'iso-8859-4': 'latin4', # north european, scandinavian, baltic
  892. 'iso-8859-5': 'iso88595', # cyrillic (ISO)
  893. 'iso-8859-9': 'latin5', # turkish
  894. 'iso-8859-15': 'latin9', # latin9, update to latin1.
  895. 'mac_cyrillic': 'maccyr', # cyrillic (on Mac)
  896. 'windows-1251': 'cp1251', # cyrillic (on Windows)
  897. 'koi8-r': 'koi8-r', # cyrillic (Russian)
  898. 'koi8-u': 'koi8-u', # cyrillic (Ukrainian)
  899. 'windows-1250': 'cp1250', #
  900. 'windows-1252': 'cp1252', #
  901. 'us-ascii': 'ascii', # ASCII (US)
  902. # unmatched encodings
  903. #'': 'applemac',
  904. #'': 'ansinew', # windows 3.1 ansi
  905. #'': 'ascii', # ASCII encoding for the range 32--127.
  906. #'': 'cp437', # dos latin us
  907. #'': 'cp850', # dos latin 1
  908. #'': 'cp852', # dos latin 2
  909. #'': 'decmulti',
  910. #'': 'latin10',
  911. #'iso-8859-6': '' # arabic
  912. #'iso-8859-7': '' # greek
  913. #'iso-8859-8': '' # hebrew
  914. #'iso-8859-10': '' # latin6, more complete iso-8859-4
  915. }
  916. encoding = docutils_encoding.lower()
  917. if encoding in tr:
  918. return tr[encoding]
  919. # convert: latin-1, latin_1, utf-8 and similar things
  920. encoding = encoding.replace('_', '').replace('-', '')
  921. # strip the error handler
  922. return encoding.split(':')[0]
  923. def language_label(self, docutil_label):
  924. return self.language.labels[docutil_label]
  925. latex_equivalents = {
  926. u'\u00A0' : '~',
  927. u'\u2013' : '{--}',
  928. u'\u2014' : '{---}',
  929. u'\u2018' : '`',
  930. u'\u2019' : "'",
  931. u'\u201A' : ',',
  932. u'\u201C' : '``',
  933. u'\u201D' : "''",
  934. u'\u201E' : ',,',
  935. u'\u2020' : '\\dag{}',
  936. u'\u2021' : '\\ddag{}',
  937. u'\u2026' : '\\dots{}',
  938. u'\u2122' : '\\texttrademark{}',
  939. u'\u21d4' : '$\\Leftrightarrow$',
  940. # greek alphabet ?
  941. }
  942. def unicode_to_latex(self,text):
  943. # see LaTeX codec
  944. # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252124
  945. # Only some special chracters are translated, for documents with many
  946. # utf-8 chars one should use the LaTeX unicode package.
  947. for uchar in self.latex_equivalents.keys():
  948. text = text.replace(uchar,self.latex_equivalents[uchar])
  949. return text
  950. def ensure_math(self, text):
  951. if not hasattr(self, 'ensure_math_re'):
  952. chars = { # lnot,pm,twosuperior,threesuperior,mu,onesuperior,times,div
  953. 'latin1' : '\xac\xb1\xb2\xb3\xb5\xb9\xd7\xf7' ,
  954. # TODO?: also latin5 and latin9
  955. }
  956. self.ensure_math_re = re.compile('([%s])' % chars['latin1'])
  957. text = self.ensure_math_re.sub(r'\\ensuremath{\1}', text)
  958. return text
  959. def encode(self, text):
  960. """Return text with special characters escaped.
  961. Escape the ten special printing characters ``# $ % & ~ _ ^ \ { }``,
  962. square brackets ``[ ]``, double quotes and (in OT1) ``< | >``.
  963. Separate ``-`` (and more in literal text) to prevent input ligatures.
  964. """
  965. if self.verbatim:
  966. return text
  967. # Bootstrapping: backslash and braces are also part of replacements
  968. # 1. backslash (terminated below)
  969. text = text.replace('\\', r'\textbackslash')
  970. # 2. braces
  971. text = text.replace('{', r'\{')
  972. text = text.replace('}', r'\}')
  973. # 3. terminate \textbackslash
  974. text = text.replace('\\textbackslash', '\\textbackslash{}')
  975. # 4. the remaining special printing characters
  976. text = text.replace('#', r'\#')
  977. text = text.replace('$', r'\$')
  978. text = text.replace('%', r'\%')
  979. text = text.replace('&', r'\&')
  980. text = text.replace('~', r'\textasciitilde{}')
  981. if not self.inside_citation_reference_label:
  982. text = text.replace('_', r'\_')
  983. text = text.replace('^', r'\textasciicircum{}')
  984. # Square brackets
  985. #
  986. # \item and all the other commands with optional arguments check
  987. # if the token right after the macro name is an opening bracket.
  988. # In that case the contents between that bracket and the following
  989. # closing bracket on the same grouping level are taken as the
  990. # optional argument. What makes this unintuitive is the fact that
  991. # the square brackets aren't grouping characters themselves, so in
  992. # your last example \item[[...]] the optional argument consists of
  993. # [... (without the closing bracket).
  994. #
  995. # How to escape?
  996. #
  997. # Square brackets are ordinary chars and cannot be escaped with '\',
  998. # so we put them in a group '{[}'. (Alternative: ensure that all
  999. # macros with optional arguments are terminated with {} and text
  1000. # inside any optional argument is put in a group ``[{text}]``).
  1001. # Commands with optional args inside an optional arg must be put
  1002. # in a group, e.g. ``\item[{\hyperref[label]{text}}]``.
  1003. text = text.replace('[', '{[}')
  1004. text = text.replace(']', '{]}')
  1005. # Workarounds for OT1 font-encoding
  1006. if self.font_encoding in ['OT1', '']:
  1007. # * out-of-order characters in cmtt
  1008. if self.literal_block or self.literal:
  1009. # replace underscore by underlined blank, because this has
  1010. # correct width.
  1011. text = text.replace(r'\_', r'\underline{ }')
  1012. # the backslash doesn't work, so we use a mirrored slash.
  1013. # \reflectbox is provided by graphicx:
  1014. self.requirements['graphicx'] = self.graphicx_package
  1015. text = text.replace(r'\textbackslash', r'\reflectbox{/}')
  1016. # * ``< | >`` come out as different chars (except for cmtt):
  1017. else:
  1018. text = text.replace('|', '\\textbar{}')
  1019. text = text.replace('<', '\\textless{}')
  1020. text = text.replace('>', '\\textgreater{}')
  1021. #
  1022. # Separate compound characters, e.g. '--' to '-{}-'. (The
  1023. # actual separation is done later; see below.)
  1024. separate_chars = '-'
  1025. if self.literal_block or self.literal:
  1026. # In monospace-font, we also separate ',,', '``' and "''"
  1027. # and some other characters which can't occur in
  1028. # non-literal text.
  1029. separate_chars += ',`\'"<>'
  1030. # double quotes are 'active' in some languages
  1031. text = text.replace('"', self.babel.literal_double_quote)
  1032. else:
  1033. text = self.babel.quote_quotes(text)
  1034. for char in separate_chars * 2:
  1035. # Do it twice ("* 2") because otherwise we would replace
  1036. # '---' by '-{}--'.
  1037. text = text.replace(char + char, char + '{}' + char)
  1038. if self.insert_newline or self.literal_block:
  1039. # Literal line breaks (in address or literal blocks):
  1040. # for blank lines, insert a protected space, to avoid
  1041. # ! LaTeX Error: There's no line here to end.
  1042. textlines = [line + '~'*(not line.lstrip())
  1043. for line in text.split('\n')]
  1044. text = '\\\\\n'.join(textlines)
  1045. if self.insert_non_breaking_blanks:
  1046. text = text.replace(' ', '~')
  1047. if not self.latex_encoding.startswith('utf8'):
  1048. text = self.unicode_to_latex(text)
  1049. text = self.ensure_math(text)
  1050. if self.latex_encoding == 'utf8':
  1051. # no-break space is not supported by (plain) utf8 input encoding
  1052. text = text.replace(u'\u00A0', '~')
  1053. return text
  1054. def attval(self, text,
  1055. whitespace=re.compile('[\n\r\t\v\f]')):
  1056. """Cleanse, encode, and return attribute value text."""
  1057. return self.encode(whitespace.sub(' ', text))
  1058. def astext(self):
  1059. """Assemble document parts and return as string."""
  1060. head = '\n'.join(self.head_prefix + self.stylesheet + self.head)
  1061. body = ''.join(self.body_prefix + self.body + self.body_suffix)
  1062. return head + '\n' + body
  1063. def is_inline(self, node):
  1064. """Check whether a node represents an inline element"""
  1065. return isinstance(node.parent, nodes.TextElement)
  1066. def append_hypertargets(self, node):
  1067. """Append hypertargets for all ids of `node`"""
  1068. # hypertarget places the anchor at the target's baseline,
  1069. # so we raise it explicitely
  1070. self.body.append('%\n'.join(['\\raisebox{1em}{\\hypertarget{%s}{}}' %
  1071. id for id in node['ids']]))
  1072. def ids_to_labels(self, node, set_anchor=True):
  1073. """Return list of label definitions for all ids of `node`
  1074. If `set_anchor` is True, an anchor is set with \phantomsection.
  1075. """
  1076. labels = ['\\label{%s}' % id for id in node.get('ids', [])]
  1077. if set_anchor and labels:
  1078. labels.insert(0, '\\phantomsection')
  1079. return labels
  1080. # Visitor methods
  1081. # ---------------
  1082. def visit_Text(self, node):
  1083. self.body.append(self.encode(node.astext()))
  1084. def depart_Text(self, node):
  1085. pass
  1086. def visit_address(self, node):
  1087. self.visit_docinfo_item(node, 'address')
  1088. def depart_address(self, node):
  1089. self.depart_docinfo_item(node)
  1090. def visit_admonition(self, node):
  1091. self.fallbacks['admonition'] = PreambleCmds.admonition
  1092. if node.tagname is 'admonition':
  1093. classes = ','.join(node['classes'])
  1094. title = ''
  1095. else: # specific admonitions
  1096. classes = node.tagname.replace('_', '-')
  1097. title = '\\DUtitle[%s]{%s}\n' % (
  1098. classes, self.language.labels.get(classes, classes))
  1099. self.body.append('\n\\DUadmonition[%s]{\n%s' % (classes, title))
  1100. def depart_admonition(self, node=None):
  1101. self.body.append('}\n')
  1102. def visit_attention(self, node):
  1103. self.visit_admonition(node)
  1104. def depart_attention(self, node):
  1105. self.depart_admonition()
  1106. def visit_author(self, node):
  1107. self.visit_docinfo_item(node, 'author')
  1108. def depart_author(self, node):
  1109. self.depart_docinfo_item(node)
  1110. def visit_authors(self, node):
  1111. # not used: visit_author is called anyway for each author.
  1112. pass
  1113. def depart_authors(self, node):
  1114. pass
  1115. def visit_block_quote(self, node):
  1116. self.body.append( '%\n\\begin{quote}\n')
  1117. def depart_block_quote(self, node):
  1118. self.body.append( '\n\\end{quote}\n')
  1119. def visit_bullet_list(self, node):
  1120. if self.is_toc_list:
  1121. self.body.append( '%\n\\begin{list}{}{}\n' )
  1122. else:
  1123. self.body.append( '%\n\\begin{itemize}\n' )
  1124. def depart_bullet_list(self, node):
  1125. if self.is_toc_list:
  1126. self.body.append( '\n\\end{list}\n' )
  1127. else:
  1128. self.body.append( '\n\\end{itemize}\n' )
  1129. def visit_superscript(self, node):
  1130. self.body.append(r'\textsuperscript{')
  1131. if node['classes']:
  1132. self.visit_inline(node)
  1133. def depart_superscript(self, node):
  1134. if node['classes']:
  1135. self.depart_inline(node)
  1136. self.body.append('}')
  1137. def visit_subscript(self, node):
  1138. self.body.append(r'\textsubscript{') # requires `fixltx2e`
  1139. if node['classes']:
  1140. self.visit_inline(node)
  1141. def depart_subscript(self, node):
  1142. if node['classes']:
  1143. self.depart_inline(node)
  1144. self.body.append('}')
  1145. def visit_caption(self, node):
  1146. self.body.append( '\\caption{' )
  1147. def depart_caption(self, node):
  1148. self.body.append('}\n')
  1149. def visit_caution(self, node):
  1150. self.visit_admonition(node)
  1151. def depart_caution(self, node):
  1152. self.depart_admonition()
  1153. def visit_title_reference(self, node):
  1154. self.fallbacks['titlereference'] = PreambleCmds.titlereference
  1155. self.body.append(r'\DUroletitlereference{')
  1156. if node['classes']:
  1157. self.visit_inline(node)
  1158. def depart_title_reference(self, node):
  1159. if node['classes']:
  1160. self.depart_inline(node)
  1161. self.body.append( '}' )
  1162. def v

Large files files are truncated, but you can click here to view the full file