Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

9560 lines (7826 sloc) 297.216 kb
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# eLyXer -- convert LyX source files to HTML output.
# Copyright (C) 2009 Alex Fernández
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <>.
# --end--
# Alex 20090308
# eLyXer main script
import sys
import os.path
import sys
import codecs
import sys
class Trace(object):
"A tracing class"
debugmode = False
quietmode = False
showlinesmode = False
prefix = None
def debug(cls, message):
"Show a debug message"
if not Trace.debugmode or Trace.quietmode:
return, sys.stdout)
def message(cls, message):
"Show a trace message"
if Trace.quietmode:
if Trace.prefix and Trace.showlinesmode:
message = Trace.prefix + message, sys.stdout)
def error(cls, message):
"Show an error message"
message = '* ' + message
if Trace.prefix and Trace.showlinesmode:
message = Trace.prefix + message, sys.stderr)
def fatal(cls, message):
"Show an error message and terminate"
Trace.error('FATAL: ' + message)
def show(cls, message, channel):
"Show a message out of a channel"
message = message.encode('utf-8')
channel.write(message + '\n')
debug = classmethod(debug)
message = classmethod(message)
error = classmethod(error)
fatal = classmethod(fatal)
show = classmethod(show)
class LineReader(object):
"Reads a file line by line"
def __init__(self, filename):
if isinstance(filename, file):
self.file = filename
self.file =, 'rU', 'utf-8')
self.linenumber = 1
self.lastline = None
self.current = None
self.mustread = True
self.depleted = False
except UnicodeDecodeError:
# try compressed file
import gzip
self.file =, 'rb')
def setstart(self, firstline):
"Set the first line to read."
for i in range(firstline):
self.linenumber = firstline
def setend(self, lastline):
"Set the last line to read."
self.lastline = lastline
def currentline(self):
"Get the current line"
if self.mustread:
return self.current
def nextline(self):
"Go to next line"
if self.depleted:
Trace.fatal('Read beyond file end')
self.mustread = True
def readline(self):
"Read a line from file"
self.current = self.file.readline()
if not isinstance(self.file, codecs.StreamReaderWriter):
self.current = self.current.decode('utf-8')
if len(self.current) == 0:
self.depleted = True
self.current = self.current.rstrip('\n\r')
self.linenumber += 1
self.mustread = False
Trace.prefix = 'Line ' + unicode(self.linenumber) + ': '
if self.linenumber % 1000 == 0:
def finished(self):
"Find out if the file is finished"
if self.lastline and self.linenumber == self.lastline:
return True
if self.mustread:
return self.depleted
def close(self):
class LineWriter(object):
"Writes a file as a series of lists"
def __init__(self, filename):
if isinstance(filename, file):
self.file = filename
self.filename = None
self.file =, 'w', "utf-8")
self.filename = filename
def write(self, strings):
"Write a list of strings"
for string in strings:
if not isinstance(string, basestring):
Trace.error('Not a string: ' + unicode(string) + ' in ' + unicode(strings))
def writestring(self, string):
"Write a string"
if self.file == sys.stdout:
string = string.encode('utf-8')
def writeline(self, line):
"Write a line to file"
self.writestring(line + '\n')
def close(self):
import os.path
import sys
class BibStylesConfig(object):
"Configuration class from config file"
abbrvnat = {
u'@article':u'$authors. $title. <i>$journal</i>,{ {$volume:}$pages,} $month $year.{ doi: $doi.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'default':u'$authors. <i>$title</i>. $publisher, $year.{ URL <a href="$url">$url</a>.}{ $note.}',
alpha = {
u'@article':u'$authors. $title.{ <i>$journal</i>{, {$volume}{($number)}}{: $pages}{, $year}.}{ <a href="$url">$url</a>.}{ <a href="$filename">$filename</a>.}{ $note.}',
u'default':u'$authors. $title.{ <i>$journal</i>,} $year.{ <a href="$url">$url</a>.}{ <a href="$filename">$filename</a>.}{ $note.}',
authordate2 = {
u'@article':u'$authors. $year. $title. <i>$journal</i>, <b>$volume</b>($number), $pages.{ URL <a href="$url">$url</a>.}{ $note.}',
u'@book':u'$authors. $year. <i>$title</i>. $publisher.{ URL <a href="$url">$url</a>.}{ $note.}',
u'cite':u'$surname, $year',
u'default':u'$authors. $year. <i>$title</i>. $publisher.{ URL <a href="$url">$url</a>.}{ $note.}',
default = {
u'@article':u'$authors: “$title”, <i>$journal</i>,{ pp. $pages,} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'@book':u'{$authors: }<i>$title</i>{ ($editor, ed.)}.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@booklet':u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@conference':u'$authors: “$title”, <i>$journal</i>,{ pp. $pages,} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'@inbook':u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@incollection':u'$authors: <i>$title</i>{ in <i>$booktitle</i>{ ($editor, ed.)}}.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@inproceedings':u'$authors: “$title”, <i>$journal</i>,{ pp. $pages,} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'@manual':u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@mastersthesis':u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@misc':u'$authors: <i>$title</i>.{{ $publisher,}{ $howpublished,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@phdthesis':u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@proceedings':u'$authors: “$title”, <i>$journal</i>,{ pp. $pages,} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'@techreport':u'$authors: <i>$title</i>, $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'@unpublished':u'$authors: “$title”, <i>$journal</i>, $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'default':u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
defaulttags = {
u'YY':u'??', u'authors':u'', u'surname':u'',
ieeetr = {
u'@article':u'$authors, “$title”, <i>$journal</i>, vol. $volume, no. $number, pp. $pages, $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'@book':u'$authors, <i>$title</i>. $publisher, $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'default':u'$authors, “$title”. $year.{ URL <a href="$url">$url</a>.}{ $note.}',
plain = {
u'@article':u'$authors. $title.{ <i>$journal</i>{, {$volume}{($number)}}{:$pages}{, $year}.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@book':u'$authors. <i>$title</i>. $publisher,{ $month} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'@incollection':u'$authors. $title.{ In <i>$booktitle</i> {($editor, ed.)}.} $publisher,{ $month} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'@inproceedings':u'$authors. $title. { <i>$booktitle</i>{, {$volume}{($number)}}{:$pages}{, $year}.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'default':u'{$authors. }$title.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
vancouver = {
u'@article':u'$authors. $title. <i>$journal</i>, $year{;{<b>$volume</b>}{($number)}{:$pages}}.{ URL: <a href="$url">$url</a>.}{ $note.}',
u'@book':u'$authors. $title. {$publisher, }$year.{ URL: <a href="$url">$url</a>.}{ $note.}',
u'default':u'$authors. $title; {$publisher, }$year.{ $howpublished.}{ URL: <a href="$url">$url</a>.}{ $note.}',
class BibTeXConfig(object):
"Configuration class from config file"
replaced = {
u'--':u'', u'..':u'.',
class ContainerConfig(object):
"Configuration class from config file"
endings = {
u'Align':u'\\end_layout', u'BarredText':u'\\bar',
u'BoldText':u'\\series', u'Cell':u'</cell',
u'ChangeInserted':u'\\change_unchanged', u'ColorText':u'\\color',
u'EmphaticText':u'\\emph', u'Hfill':u'\\hfill', u'Inset':u'\\end_inset',
u'Layout':u'\\end_layout', u'LyXFooter':u'\\end_document',
u'LyXHeader':u'\\end_header', u'Row':u'</row', u'ShapedText':u'\\shape',
u'SizeText':u'\\size', u'StrikeOut':u'\\strikeout',
u'TextFamily':u'\\family', u'VersalitasText':u'\\noun',
extracttext = {
startendings = {
u'\\begin_deeper':u'\\end_deeper', u'\\begin_inset':u'\\end_inset',
starts = {
u'':u'StringContainer', u'#LyX':u'BlackBox', u'</lyxtabular':u'BlackBox',
u'<cell':u'Cell', u'<column':u'Column', u'<row':u'Row',
u'\\align':u'Align', u'\\bar':u'BarredText',
u'\\bar default':u'BlackBox', u'\\bar no':u'BlackBox',
u'\\begin_body':u'BlackBox', u'\\begin_deeper':u'DeeperList',
u'\\begin_document':u'BlackBox', u'\\begin_header':u'LyXHeader',
u'\\begin_inset Argument':u'ShortTitle',
u'\\begin_inset Box':u'BoxInset', u'\\begin_inset Branch':u'Branch',
u'\\begin_inset Caption':u'Caption',
u'\\begin_inset CommandInset bibitem':u'BiblioEntry',
u'\\begin_inset CommandInset bibtex':u'BibTeX',
u'\\begin_inset CommandInset citation':u'BiblioCitation',
u'\\begin_inset CommandInset href':u'URL',
u'\\begin_inset CommandInset include':u'IncludeInset',
u'\\begin_inset CommandInset index_print':u'PrintIndex',
u'\\begin_inset CommandInset label':u'Label',
u'\\begin_inset CommandInset line':u'LineInset',
u'\\begin_inset CommandInset nomencl_print':u'PrintNomenclature',
u'\\begin_inset CommandInset nomenclature':u'NomenclatureEntry',
u'\\begin_inset CommandInset ref':u'Reference',
u'\\begin_inset CommandInset toc':u'TableOfContents',
u'\\begin_inset ERT':u'ERT', u'\\begin_inset Flex':u'FlexInset',
u'\\begin_inset Flex Chunkref':u'NewfangledChunkRef',
u'\\begin_inset Flex Marginnote':u'SideNote',
u'\\begin_inset Flex Sidenote':u'SideNote',
u'\\begin_inset Flex URL':u'FlexURL', u'\\begin_inset Float':u'Float',
u'\\begin_inset FloatList':u'ListOf', u'\\begin_inset Foot':u'Footnote',
u'\\begin_inset Formula':u'Formula',
u'\\begin_inset FormulaMacro':u'FormulaMacro',
u'\\begin_inset Graphics':u'Image',
u'\\begin_inset Index':u'IndexReference',
u'\\begin_inset Info':u'InfoInset',
u'\\begin_inset LatexCommand bibitem':u'BiblioEntry',
u'\\begin_inset LatexCommand bibtex':u'BibTeX',
u'\\begin_inset LatexCommand cite':u'BiblioCitation',
u'\\begin_inset LatexCommand citealt':u'BiblioCitation',
u'\\begin_inset LatexCommand citep':u'BiblioCitation',
u'\\begin_inset LatexCommand citet':u'BiblioCitation',
u'\\begin_inset LatexCommand htmlurl':u'URL',
u'\\begin_inset LatexCommand index':u'IndexReference',
u'\\begin_inset LatexCommand label':u'Label',
u'\\begin_inset LatexCommand nomenclature':u'NomenclatureEntry',
u'\\begin_inset LatexCommand prettyref':u'Reference',
u'\\begin_inset LatexCommand printindex':u'PrintIndex',
u'\\begin_inset LatexCommand printnomenclature':u'PrintNomenclature',
u'\\begin_inset LatexCommand ref':u'Reference',
u'\\begin_inset LatexCommand tableofcontents':u'TableOfContents',
u'\\begin_inset LatexCommand url':u'URL',
u'\\begin_inset LatexCommand vref':u'Reference',
u'\\begin_inset Marginal':u'SideNote',
u'\\begin_inset Newline':u'NewlineInset',
u'\\begin_inset Newpage':u'NewPageInset', u'\\begin_inset Note':u'Note',
u'\\begin_inset OptArg':u'ShortTitle',
u'\\begin_inset Phantom':u'PhantomText',
u'\\begin_inset Quotes':u'QuoteContainer',
u'\\begin_inset Tabular':u'Table', u'\\begin_inset Text':u'InsetText',
u'\\begin_inset VSpace':u'VerticalSpace', u'\\begin_inset Wrap':u'Wrap',
u'\\begin_inset listings':u'Listing', u'\\begin_inset space':u'Space',
u'\\begin_layout':u'Layout', u'\\begin_layout Abstract':u'Abstract',
u'\\begin_layout Author':u'Author',
u'\\begin_layout Bibliography':u'Bibliography',
u'\\begin_layout Chunk':u'NewfangledChunk',
u'\\begin_layout Description':u'Description',
u'\\begin_layout Enumerate':u'ListItem',
u'\\begin_layout Itemize':u'ListItem', u'\\begin_layout List':u'List',
u'\\begin_layout LyX-Code':u'LyXCode',
u'\\begin_layout Plain':u'PlainLayout',
u'\\begin_layout Standard':u'StandardLayout',
u'\\begin_layout Title':u'Title', u'\\begin_preamble':u'LyXPreamble',
u'\\change_unchanged':u'BlackBox', u'\\color':u'ColorText',
u'\\color inherit':u'BlackBox', u'\\color none':u'BlackBox',
u'\\emph default':u'BlackBox', u'\\emph off':u'BlackBox',
u'\\emph on':u'EmphaticText', u'\\emph toggle':u'EmphaticText',
u'\\end_body':u'LyXFooter', u'\\family':u'TextFamily',
u'\\family default':u'BlackBox', u'\\family roman':u'BlackBox',
u'\\hfill':u'Hfill', u'\\labelwidthstring':u'BlackBox',
u'\\lang':u'LangLine', u'\\length':u'InsetLength',
u'\\lyxformat':u'LyXFormat', u'\\lyxline':u'LyXLine',
u'\\newline':u'Newline', u'\\newpage':u'NewPage',
u'\\noindent':u'BlackBox', u'\\noun default':u'BlackBox',
u'\\noun off':u'BlackBox', u'\\noun on':u'VersalitasText',
u'\\paragraph_spacing':u'BlackBox', u'\\series bold':u'BoldText',
u'\\series default':u'BlackBox', u'\\series medium':u'BlackBox',
u'\\shape':u'ShapedText', u'\\shape default':u'BlackBox',
u'\\shape up':u'BlackBox', u'\\size':u'SizeText',
u'\\size normal':u'BlackBox', u'\\start_of_appendix':u'StartAppendix',
u'\\strikeout default':u'BlackBox', u'\\strikeout on':u'StrikeOut',
string = {
table = {
class EscapeConfig(object):
"Configuration class from config file"
chars = {
u'\n':u'', u' -- ':u'', u'\'':u'', u'---':u'', u'`':u'',
commands = {
u'\\InsetSpace \\space{}':u' ', u'\\InsetSpace \\thinspace{}':u'',
u'\\InsetSpace ~':u' ', u'\\SpecialChar \\-':u'',
u'\\SpecialChar \\@.':u'.', u'\\SpecialChar \\ldots{}':u'',
u'\\SpecialChar \\menuseparator':u' ▷ ',
u'\\SpecialChar \\nobreakdash-':u'-', u'\\SpecialChar \\slash{}':u'/',
u'\\SpecialChar \\textcompwordmark{}':u'', u'\\backslash':u'\\',
entities = {
u'&':u'&amp;', u'<':u'&lt;', u'>':u'&gt;',
html = {
iso885915 = {
u' ':u'&nbsp;', u'':u'&emsp;', u'':u'&#8197;',
nonunicode = {
class FormulaConfig(object):
"Configuration class from config file"
alphacommands = {
u'\\AA':u'Å', u'\\AE':u'Æ', u'\\DH':u'Ð', u'\\L':u'Ł', u'\\O':u'Ø',
u'\\OE':u'Œ', u'\\TH':u'Þ', u'\\aa':u'å', u'\\ae':u'æ', u'\\alpha':u'α',
u'\\beta':u'β', u'\\delta':u'δ', u'\\dh':u'ð', u'\\epsilon':u'ϵ',
u'\\eta':u'η', u'\\gamma':u'γ', u'\\i':u'ı', u'\\imath':u'ı',
u'\\iota':u'ι', u'\\j':u'ȷ', u'\\jmath':u'ȷ', u'\\kappa':u'κ',
u'\\l':u'ł', u'\\lambda':u'λ', u'\\mu':u'μ', u'\\nu':u'ν', u'\\o':u'ø',
u'\\oe':u'œ', u'\\omega':u'ω', u'\\phi':u'φ', u'\\pi':u'π',
u'\\psi':u'ψ', u'\\rho':u'ρ', u'\\sigma':u'σ', u'\\ss':u'ß',
u'\\tau':u'τ', u'\\textcrh':u'ħ', u'\\th':u'þ', u'\\theta':u'θ',
u'\\upsilon':u'υ', u'\\varDelta':u'', u'\\varGamma':u'Γ',
u'\\varLambda':u'Λ', u'\\varOmega':u'Ω', u'\\varPhi':u'Φ',
u'\\varPi':u'Π', u'\\varPsi':u'Ψ', u'\\varSigma':u'Σ',
u'\\varTheta':u'Θ', u'\\varUpsilon':u'Υ', u'\\varXi':u'Ξ',
u'\\varepsilon':u'ε', u'\\varkappa':u'ϰ', u'\\varphi':u'φ',
u'\\varpi':u'ϖ', u'\\varrho':u'ϱ', u'\\varsigma':u'ς',
u'\\vartheta':u'ϑ', u'\\xi':u'ξ', u'\\zeta':u'ζ',
array = {
u'begin':u'\\begin', u'cellseparator':u'&', u'end':u'\\end',
bigbrackets = {
u'(':[u'',u'',u'',], u')':[u'',u'',u'',], u'[':[u'',u'',u'',],
binomialfunctions = {
u'\\dbinom':[u'(',u')',], u'\\tbinom':[u'(',u')',],
bracketcommands = {
u'\\left':u'span class="symbol"',
u'\\left.':u'<span class="leftdot"></span>',
u'\\middle':u'span class="symbol"', u'\\right':u'span class="symbol"',
u'\\right.':u'<span class="rightdot"></span>',
combiningfunctions = {
u'\\"':u'̈', u'\\\'':u'́', u'\\^':u'̂', u'\\`':u'̀', u'\\acute':u'́',
u'\\bar':u'̄', u'\\breve':u'̆', u'\\c':u'̧', u'\\check':u'̌',
u'\\dddot':u'', u'\\ddot':u'̈', u'\\dot':u'̇', u'\\grave':u'̀',
u'\\hat':u'̂', u'\\mathring':u'̊', u'\\overleftarrow':u'',
u'\\overrightarrow':u'', u'\\r':u'̥', u'\\s':u'̩',
u'\\textsubring':u'̥', u'\\tilde':u'̃', u'\\vec':u'', u'\\~':u'̃',
commands = {
u'\\ ':u' ', u'\\!':u'', u'\\#':u'#', u'\\$':u'$', u'\\%':u'%',
u'\\&#38;':u'&', u'\\,':u' ', u'\\:':u'', u'\\;':u'',
u'\\APLdownarrowbox':u'', u'\\APLleftarrowbox':u'',
u'\\APLrightarrowbox':u'', u'\\APLuparrowbox':u'', u'\\Box':u'',
u'\\Bumpeq':u'', u'\\CIRCLE':u'', u'\\Cap':u'', u'\\CheckedBox':u'',
u'\\Circle':u'', u'\\Coloneqq':u'', u'\\Corresponds':u'',
u'\\Cup':u'', u'\\Delta':u'Δ', u'\\Diamond':u'', u'\\Downarrow':u'',
u'\\EUR':u'', u'\\Gamma':u'Γ', u'\\Im':u'', u'\\Join':u'',
u'\\LEFTCIRCLE':u'', u'\\LEFTcircle':u'', u'\\Lambda':u'Λ',
u'\\Leftarrow':u'', u'\\Lleftarrow':u'', u'\\Longleftarrow':u'',
u'\\Longleftrightarrow':u'', u'\\Longrightarrow':u'', u'\\Lsh':u'',
u'\\Mapsfrom':u'⇐|', u'\\Mapsto':u'|⇒', u'\\Omega':u'Ω', u'\\P':u'',
u'\\Phi':u'Φ', u'\\Pi':u'Π', u'\\Pr':u'Pr', u'\\Psi':u'Ψ',
u'\\RIGHTCIRCLE':u'', u'\\RIGHTcircle':u'', u'\\Re':u'',
u'\\Rrightarrow':u'', u'\\Rsh':u'', u'\\S':u'§', u'\\Sigma':u'Σ',
u'\\Square':u'', u'\\Subset':u'', u'\\Supset':u'', u'\\Theta':u'Θ',
u'\\Uparrow':u'', u'\\Updownarrow':u'', u'\\Upsilon':u'Υ',
u'\\Vdash':u'', u'\\Vert':u'', u'\\Vvdash':u'', u'\\XBox':u'',
u'\\Xi':u'Ξ', u'\\Yup':u'', u'\\\\':u'<br/>', u'\\_':u'_',
u'\\aleph':u'', u'\\amalg':u'', u'\\angle':u'', u'\\aquarius':u'',
u'\\arccos':u'arccos', u'\\arcsin':u'arcsin', u'\\arctan':u'arctan',
u'\\arg':u'arg', u'\\aries':u'', u'\\ast':u'', u'\\asymp':u'',
u'\\backepsilon':u'', u'\\backprime':u'', u'\\backsimeq':u'',
u'\\backslash':u'\\', u'\\barwedge':u'', u'\\because':u'',
u'\\beth':u'', u'\\between':u'', u'\\bigcap':u'', u'\\bigcirc':u'',
u'\\bigcup':u'', u'\\bigodot':u'', u'\\bigoplus':u'',
u'\\bigotimes':u'', u'\\bigsqcup':u'', u'\\bigstar':u'',
u'\\bigtriangledown':u'', u'\\bigtriangleup':u'', u'\\biguplus':u'',
u'\\bigvee':u'', u'\\bigwedge':u'', u'\\blacklozenge':u'',
u'\\blacksmiley':u'', u'\\blacksquare':u'', u'\\blacktriangle':u'',
u'\\blacktriangledown':u'', u'\\blacktriangleright':u'', u'\\bot':u'',
u'\\bowtie':u'', u'\\box':u'', u'\\boxdot':u'', u'\\bullet':u'',
u'\\bumpeq':u'', u'\\cancer':u'', u'\\cap':u'', u'\\capricornus':u'',
u'\\cdot':u'', u'\\cdots':u'', u'\\centerdot':u'',
u'\\checkmark':u'', u'\\chi':u'χ', u'\\circ':u'', u'\\circeq':u'',
u'\\circledR':u'®', u'\\circledast':u'', u'\\circledcirc':u'',
u'\\circleddash':u'', u'\\clubsuit':u'', u'\\coloneqq':u'',
u'\\complement':u'', u'\\cong':u'', u'\\coprod':u'',
u'\\copyright':u'©', u'\\cos':u'cos', u'\\cosh':u'cosh', u'\\cot':u'cot',
u'\\coth':u'coth', u'\\csc':u'csc', u'\\cup':u'',
u'\\curvearrowleft':u'', u'\\curvearrowright':u'', u'\\dag':u'',
u'\\dagger':u'', u'\\daleth':u'', u'\\dashleftarrow':u'',
u'\\dashv':u'', u'\\ddag':u'', u'\\ddagger':u'', u'\\ddots':u'',
u'\\deg':u'deg', u'\\det':u'det', u'\\diagdown':u'', u'\\diagup':u'',
u'\\diamond':u'', u'\\diamondsuit':u'', u'\\dim':u'dim',
u'\\displaystyle':u'', u'\\div':u'÷', u'\\divideontimes':u'',
u'\\dotdiv':u'', u'\\doteq':u'', u'\\doteqdot':u'', u'\\dotplus':u'',
u'\\dots':u'', u'\\doublebarwedge':u'', u'\\downarrow':u'',
u'\\downdownarrows':u'', u'\\downharpoonleft':u'',
u'\\downharpoonright':u'', u'\\earth':u'', u'\\ell':u'',
u'\\emptyset':u'', u'\\eqcirc':u'', u'\\eqcolon':u'', u'\\eqsim':u'',
u'\\euro':u'', u'\\exists':u'', u'\\exp':u'exp',
u'\\fallingdotseq':u'', u'\\female':u'', u'\\flat':u'',
u'\\forall':u'', u'\\frown':u'', u'\\frownie':u'', u'\\gcd':u'gcd',
u'\\gemini':u'', u'\\geq)':u'', u'\\geqq':u'', u'\\geqslant':u'',
u'\\gets':u'', u'\\gg':u'', u'\\ggg':u'', u'\\gimel':u'',
u'\\gneqq':u'', u'\\gnsim':u'', u'\\gtrdot':u'', u'\\gtreqless':u'',
u'\\gtreqqless':u'', u'\\gtrless':u'', u'\\gtrsim':u'',
u'\\hbar':u'', u'\\heartsuit':u'',
u'\\hfill':u'<span class="hfill"> </span>', u'\\hom':u'hom',
u'\\hookleftarrow':u'', u'\\hookrightarrow':u'', u'\\hslash':u'',
u'\\idotsint':u'<span class="bigsymbol">∫⋯∫</span>',
u'\\iiint':u'<span class="bigsymbol">∭</span>',
u'\\iint':u'<span class="bigsymbol">∬</span>', u'\\imath':u'ı',
u'\\inf':u'inf', u'\\infty':u'', u'\\invneg':u'', u'\\jmath':u'ȷ',
u'\\jupiter':u'', u'\\ker':u'ker', u'\\land':u'',
u'\\landupint':u'<span class="bigsymbol">∱</span>', u'\\langle':u'',
u'\\lbrace':u'{', u'\\lbrace)':u'{', u'\\lbrack':u'[', u'\\lceil':u'',
u'\\ldots':u'', u'\\leadsto':u'', u'\\leftarrow)':u'',
u'\\leftarrowtail':u'', u'\\leftarrowtobar':u'',
u'\\leftharpoondown':u'', u'\\leftharpoonup':u'',
u'\\leftleftarrows':u'', u'\\leftleftharpoons':u'', u'\\leftmoon':u'',
u'\\leftrightarrow':u'', u'\\leftrightarrows':u'',
u'\\leftrightharpoons':u'', u'\\leftthreetimes':u'', u'\\leo':u'',
u'\\leq)':u'', u'\\leqq':u'', u'\\leqslant':u'', u'\\lessdot':u'',
u'\\lesseqgtr':u'', u'\\lesseqqgtr':u'', u'\\lessgtr':u'',
u'\\lesssim':u'', u'\\lfloor':u'', u'\\lg':u'lg', u'\\lhd':u'',
u'\\libra':u'', u'\\lightning':u'', u'\\liminf':u'liminf',
u'\\limsup':u'limsup', u'\\ll':u'', u'\\lll':u'', u'\\ln':u'ln',
u'\\lneqq':u'', u'\\lnot':u'¬', u'\\lnsim':u'', u'\\log':u'log',
u'\\longleftarrow':u'', u'\\longleftrightarrow':u'',
u'\\longmapsto':u'', u'\\longrightarrow':u'', u'\\looparrowleft':u'',
u'\\looparrowright':u'', u'\\lor':u'', u'\\lozenge':u'',
u'\\ltimes':u'', u'\\lyxlock':u'', u'\\male':u'', u'\\maltese':u'',
u'\\mapsfrom':u'', u'\\mapsto':u'', u'\\mathcircumflex':u'^',
u'\\max':u'max', u'\\measuredangle':u'', u'\\mercury':u'',
u'\\mho':u'', u'\\mid':u'', u'\\min':u'min', u'\\models':u'',
u'\\mp':u'', u'\\multimap':u'', u'\\nLeftarrow':u'',
u'\\nLeftrightarrow':u'', u'\\nRightarrow':u'', u'\\nVDash':u'',
u'\\nabla':u'', u'\\napprox':u'', u'\\natural':u'', u'\\ncong':u'',
u'\\nearrow':u'', u'\\neg':u'¬', u'\\neg)':u'¬', u'\\neptune':u'',
u'\\nequiv':u'', u'\\newline':u'<br/>', u'\\nexists':u'',
u'\\ngeqslant':u'', u'\\ngtr':u'', u'\\ngtrless':u'', u'\\ni':u'',
u'\\ni)':u'', u'\\nleftarrow':u'', u'\\nleftrightarrow':u'',
u'\\nleqslant':u'', u'\\nless':u'', u'\\nlessgtr':u'', u'\\nmid':u'',
u'\\nonumber':u'', u'\\not':u'¬', u'\\not<':u'', u'\\not=':u'',
u'\\not>':u'', u'\\notbackslash':u'', u'\\notin':u'', u'\\notni':u'',
u'\\notslash':u'', u'\\nparallel':u'', u'\\nprec':u'',
u'\\nrightarrow':u'', u'\\nsim':u'', u'\\nsimeq':u'',
u'\\nsqsubset':u'⊏̸', u'\\nsubseteq':u'', u'\\nsucc':u'',
u'\\nsucccurlyeq':u'', u'\\nsupset':u'', u'\\nsupseteq':u'',
u'\\ntriangleleft':u'', u'\\ntrianglelefteq':u'',
u'\\ntriangleright':u'', u'\\ntrianglerighteq':u'', u'\\nvDash':u'',
u'\\nvdash':u'', u'\\nwarrow':u'', u'\\odot':u'',
u'\\officialeuro':u'', u'\\oiiint':u'<span class="bigsymbol">∰</span>',
u'\\oiint':u'<span class="bigsymbol">∯</span>',
u'\\oint':u'<span class="bigsymbol">∮</span>',
u'\\ointclockwise':u'<span class="bigsymbol">∲</span>',
u'\\ointctrclockwise':u'<span class="bigsymbol">∳</span>',
u'\\ominus':u'', u'\\oplus':u'', u'\\oslash':u'', u'\\otimes':u'',
u'\\owns':u'', u'\\parallel':u'', u'\\partial':u'', u'\\perp':u'',
u'\\pisces':u'', u'\\pitchfork':u'', u'\\pluto':u'', u'\\pm':u'±',
u'\\pointer':u'', u'\\pounds':u'£', u'\\prec':u'',
u'\\preccurlyeq':u'', u'\\preceq':u'', u'\\precsim':u'',
u'\\prime':u'', u'\\prompto':u'', u'\\qquad':u' ', u'\\quad':u' ',
u'\\quarternote':u'', u'\\rangle':u'', u'\\rbrace':u'}',
u'\\rbrace)':u'}', u'\\rbrack':u']', u'\\rceil':u'', u'\\rfloor':u'',
u'\\rhd':u'', u'\\rightarrow)':u'', u'\\rightarrowtail':u'',
u'\\rightarrowtobar':u'', u'\\rightharpoondown':u'',
u'\\rightharpoonup':u'', u'\\rightharpooondown':u'',
u'\\rightharpooonup':u'', u'\\rightleftarrows':u'',
u'\\rightleftharpoons':u'', u'\\rightmoon':u'',
u'\\rightrightarrows':u'', u'\\rightrightharpoons':u'',
u'\\rightthreetimes':u'', u'\\risingdotseq':u'', u'\\rtimes':u'',
u'\\sagittarius':u'', u'\\saturn':u'', u'\\scorpio':u'',
u'\\scriptscriptstyle':u'', u'\\scriptstyle':u'', u'\\searrow':u'',
u'\\sec':u'sec', u'\\setminus':u'', u'\\sharp':u'', u'\\simeq':u'',
u'\\sin':u'sin', u'\\sinh':u'sinh', u'\\slash':u'', u'\\smile':u'',
u'\\smiley':u'', u'\\spadesuit':u'', u'\\sphericalangle':u'',
u'\\sqcap':u'', u'\\sqcup':u'', u'\\sqsubset':u'',
u'\\sqsubseteq':u'', u'\\sqsupset':u'', u'\\sqsupseteq':u'',
u'\\square':u'', u'\\star':u'', u'\\subseteqq':u'',
u'\\subsetneqq':u'', u'\\succ':u'', u'\\succcurlyeq':u'',
u'\\succeq':u'', u'\\succnsim':u'', u'\\succsim':u'', u'\\sun':u'',
u'\\sup':u'sup', u'\\supseteqq':u'', u'\\supsetneqq':u'',
u'\\surd':u'', u'\\swarrow':u'', u'\\tan':u'tan', u'\\tanh':u'tanh',
u'\\taurus':u'', u'\\textasciicircum':u'^', u'\\textasciitilde':u'~',
u'\\textbackslash':u'\\', u'\\textendash':u'', u'\\textgreater':u'>',
u'\\textless':u'<', u'\\textordfeminine':u'ª',
u'\\textordmasculine':u'º', u'\\textquotedblleft':u'',
u'\\textquotedblright':u'', u'\\textregistered':u'®',
u'\\textstyle':u'', u'\\texttrademark':u'', u'\\therefore':u'',
u'\\top':u'', u'\\triangle':u'', u'\\triangleleft':u'',
u'\\trianglelefteq':u'', u'\\triangleq':u'', u'\\triangleright':u'',
u'\\trianglerighteq':u'', u'\\twoheadleftarrow':u'',
u'\\twoheadrightarrow':u'', u'\\twonotes':u'', u'\\udot':u'',
u'\\unlhd':u'', u'\\unrhd':u'', u'\\unrhl':u'', u'\\uparrow':u'',
u'\\updownarrow':u'', u'\\upharpoonleft':u'', u'\\upharpoonright':u'',
u'\\uplus':u'', u'\\upuparrows':u'', u'\\uranus':u'', u'\\vDash':u'',
u'\\varclubsuit':u'', u'\\vardiamondsuit':u'', u'\\varheartsuit':u'',
u'\\varnothing':u'', u'\\varspadesuit':u'', u'\\vdash':u'',
u'\\vdots':u'', u'\\vee':u'', u'\\vee)':u'', u'\\veebar':u'',
u'\\vert':u'', u'\\virgo':u'', u'\\wedge':u'', u'\\wedge)':u'',
u'\\wp':u'', u'\\wr':u'', u'\\yen':u'¥', u'\\{':u'{', u'\\|':u'',
decoratedcommand = {
decoratingfunctions = {
u'\\overleftarrow':u'', u'\\overrightarrow':u'', u'\\widehat':u'^',
definingfunctions = {
endings = {
u'bracket':u'}', u'complex':u'\\]', u'endafter':u'}',
u'endbefore':u'\\end{', u'squarebracket':u']',
environments = {
u'align':[u'r',u'l',], u'eqnarray':[u'r',u'c',u'l',],
fontfunctions = {
u'\\boldsymbol':u'b', u'\\mathbb':u'span class="blackboard"',
u'\\mathbb{A}':u'𝔸', u'\\mathbb{B}':u'𝔹', u'\\mathbb{C}':u'',
u'\\mathbb{D}':u'𝔻', u'\\mathbb{E}':u'𝔼', u'\\mathbb{F}':u'𝔽',
u'\\mathbb{G}':u'𝔾', u'\\mathbb{H}':u'', u'\\mathbb{J}':u'𝕁',
u'\\mathbb{K}':u'𝕂', u'\\mathbb{L}':u'𝕃', u'\\mathbb{N}':u'',
u'\\mathbb{O}':u'𝕆', u'\\mathbb{P}':u'', u'\\mathbb{Q}':u'',
u'\\mathbb{R}':u'', u'\\mathbb{S}':u'𝕊', u'\\mathbb{T}':u'𝕋',
u'\\mathbb{W}':u'𝕎', u'\\mathbb{Z}':u'', u'\\mathbf':u'b',
u'\\mathcal':u'span class="script"',
u'\\mathfrak':u'span class="fraktur"', u'\\mathfrak{C}':u'',
u'\\mathfrak{F}':u'𝔉', u'\\mathfrak{H}':u'', u'\\mathfrak{I}':u'',
u'\\mathfrak{R}':u'', u'\\mathfrak{Z}':u'', u'\\mathit':u'i',
u'\\mathring{A}':u'Å', u'\\mathring{U}':u'Ů', u'\\mathring{a}':u'å',
u'\\mathring{u}':u'ů', u'\\mathring{w}':u'', u'\\mathring{y}':u'',
u'\\mathrm':u'span class="mathrm"', u'\\mathscr':u'span class="script"',
u'\\mathscr{B}':u'', u'\\mathscr{E}':u'', u'\\mathscr{F}':u'',
u'\\mathscr{H}':u'', u'\\mathscr{I}':u'', u'\\mathscr{L}':u'',
u'\\mathscr{M}':u'', u'\\mathscr{R}':u'',
u'\\mathsf':u'span class="mathsf"', u'\\mathtt':u'tt',
hybridfunctions = {
u'\\binom':[u'{$1}{$2}',u'f2{(}f0{f1{$1}f1{$2}}f2{)}',u'span class="binom"',u'span class="binomstack"',u'span class="bigsymbol"',],
u'\\boxed':[u'{$1}',u'f0{$1}',u'span class="boxed"',],
u'\\cfrac':[u'[$p!]{$1}{$2}',u'f0{f3{(}f1{$1}f3{)/(}f2{$2}f3{)}}',u'span class="fullfraction"',u'span class="numerator align-$p"',u'span class="denominator"',u'span class="ignored"',],
u'\\color':[u'{$p!}{$1}',u'f0{$1}',u'span style="color: $p;"',],
u'\\colorbox':[u'{$p!}{$1}',u'f0{$1}',u'span class="colorbox" style="background: $p;"',],
u'\\dfrac':[u'{$1}{$2}',u'f0{f3{(}f1{$1}f3{)/(}f2{$2}f3{)}}',u'span class="fullfraction"',u'span class="numerator"',u'span class="denominator"',u'span class="ignored"',],
u'\\fbox':[u'{$1}',u'f0{$1}',u'span class="fbox"',],
u'\\fcolorbox':[u'{$p!}{$q!}{$1}',u'f0{$1}',u'span class="boxed" style="border-color: $p; background: $q;"',],
u'\\frac':[u'{$1}{$2}',u'f0{f3{(}f1{$1}f3{)/(}f2{$2}f3{)}}',u'span class="fraction"',u'span class="numerator"',u'span class="denominator"',u'span class="ignored"',],
u'\\framebox':[u'[$p!][$q!]{$1}',u'f0{$1}',u'span class="framebox align-$q" style="width: $p;"',],
u'\\href':[u'[$o]{$u!}{$t!}',u'f0{$t}',u'a href="$u"',],
u'\\hspace':[u'{$p!}',u'f0{ }',u'span class="hspace" style="width: $p;"',],
u'\\leftroot':[u'{$p!}',u'f0{ }',u'span class="leftroot" style="width: $p;px"',],
u'\\nicefrac':[u'{$1}{$2}',u'f0{f1{$1}⁄f2{$2}}',u'span class="fraction"',u'sup class="numerator"',u'sub class="denominator"',u'span class="ignored"',],
u'\\raisebox':[u'{$p!}{$1}',u'f0{$1}',u'span class="raisebox" style="vertical-align: $p;"',],
u'\\sqrt':[u'[$0]{$1}',u'f0{f1{$0}f2{√}f4{(}f3{$1}f4{)}}',u'span class="sqrt"',u'sup class="root"',u'span class="radical"',u'span class="root"',u'span class="ignored"',],
u'\\stackrel':[u'{$1}{$2}',u'f0{f1{$1}f2{$2}}',u'span class="stackrel"',u'span class="upstackrel"',u'span class="downstackrel"',],
u'\\textcolor':[u'{$p!}{$1}',u'f0{$1}',u'span style="color: $p;"',],
u'\\unit':[u'[$0]{$1}',u'$0f0{$1.font}',u'span class="unit"',],
u'\\unitfrac':[u'[$0]{$1}{$2}',u'$0f0{f1{$1.font}⁄f2{$2.font}}',u'span class="fraction"',u'sup class="unit"',u'sub class="unit"',],
u'\\uproot':[u'{$p!}',u'f0{ }',u'span class="uproot" style="width: $p;px"',],
u'\\url':[u'{$u!}',u'f0{$u}',u'a href="$u"',],
u'\\vspace':[u'{$p!}',u'f0{ }',u'span class="vspace" style="height: $p;"',],
labelfunctions = {
u'\\label':u'a name="#"',
limitcommands = {
u'\\int':[u'<span class="bigsymbol">∫</span>',u'',u'',],
u'\\intop':[u'<span class="bigsymbol">∫</span>',u'',u'',],
u'\\lim':[u'lim',], u'\\prod':[u'',], u'\\smallint':[u'',],
u'\\sum':[u'<span class="bigsymbol">∑</span>',u'',u'',],
modified = {
u'\n':u'', u' ':u'', u'$':u'', u'&':u' ', u'\'':u'', u'+':u' + ',
u',':u', ', u'-':u' − ', u'/':u' ⁄ ', u'<':u' &lt; ', u'=':u' = ',
u'>':u' &gt; ', u'@':u'', u'~':u'',
onefunctions = {
u'\\Big':u'span class="bigsymbol"', u'\\Bigg':u'span class="hugesymbol"',
u'\\bar':u'span class="bar"', u'\\begin{array}':u'span class="arraydef"',
u'\\big':u'span class="symbol"', u'\\bigg':u'span class="largesymbol"',
u'\\bigl':u'span class="bigsymbol"', u'\\bigr':u'span class="bigsymbol"',
u'\\ensuremath':u'span class="ensuremath"',
u'\\hphantom':u'span class="phantom"',
u'\\overbrace':u'span class="overbrace"',
u'\\overline':u'span class="overline"',
u'\\phantom':u'span class="phantom"',
u'\\underbrace':u'span class="underbrace"', u'\\underline':u'u',
u'\\vphantom':u'span class="phantom"',
preamblefunctions = {
spacedcommands = {
u'\\Leftrightarrow':u'', u'\\Rightarrow':u'', u'\\approx':u'',
u'\\dashrightarrow':u'', u'\\equiv':u'', u'\\ge':u'', u'\\geq':u'',
u'\\implies':u' ⇒ ', u'\\in':u'', u'\\le':u'', u'\\leftarrow':u'',
u'\\leq':u'', u'\\ne':u'', u'\\neq':u'', u'\\not\\in':u'',
u'\\propto':u'', u'\\rightarrow':u'', u'\\rightsquigarrow':u'',
u'\\sim':u'~', u'\\subset':u'', u'\\subseteq':u'', u'\\supset':u'',
u'\\supseteq':u'', u'\\times':u'×', u'\\to':u'',
starts = {
u'beginafter':u'}', u'beginbefore':u'\\begin{', u'bracket':u'{',
u'command':u'\\', u'comment':u'%', u'complex':u'\\[', u'simple':u'$',
u'squarebracket':u'[', u'unnumbered':u'*',
symbolfunctions = {
u'^':u'sup', u'_':u'sub',
textfunctions = {
u'\\mbox':u'span class="mbox"', u'\\text':u'span class="text"',
u'\\textbf':u'b', u'\\textipa':u'span class="textipa"', u'\\textit':u'i',
u'\\textnormal':u'span class="textnormal"',
u'\\textrm':u'span class="textrm"',
u'\\textsc':u'span class="versalitas"',
u'\\textsf':u'span class="textsf"', u'\\textsl':u'i', u'\\texttt':u'tt',
u'\\textup':u'span class="normal"',
unmodified = {
class GeneralConfig(object):
"Configuration class from config file"
version = {
u'date':u'2010-12-23', u'lyxformat':u'398', u'number':u'1.1.2',
class HeaderConfig(object):
"Configuration class from config file"
parameters = {
u'beginpreamble':u'\\begin_preamble', u'branch':u'\\branch',
u'documentclass':u'\\textclass', u'endbranch':u'\\end_branch',
u'endpreamble':u'\\end_preamble', u'language':u'\\language',
u'lstset':u'\\lstset', u'outputchanges':u'\\output_changes',
u'pdftitle':u'\\pdf_title', u'secnumdepth':u'\\secnumdepth',
styles = {
class ImageConfig(object):
"Configuration class from config file"
converters = {
u'imagemagick':u'convert[ -density $scale][ -define $format:use-cropbox=true] "$input" "$output"',
u'inkscape':u'inkscape "$input" --export-png="$output"',
cropboxformats = {
u'.eps':u'ps', u'.pdf':u'pdf', u'.ps':u'ps',
formats = {
u'default':u'.png', u'vector':[u'.svg',u'.eps',],
class LayoutConfig(object):
"Configuration class from config file"
groupable = {
class NewfangleConfig(object):
"Configuration class from config file"
constants = {
u'chunkref':u'chunkref{', u'endcommand':u'}', u'endmark':u'&gt;',
u'startcommand':u'\\', u'startmark':u'=&lt;',
class NumberingConfig(object):
"Configuration class from config file"
layouts = {
sequence = {
class StyleConfig(object):
"Configuration class from config file"
hspaces = {
u'\\enskip{}':u'', u'\\hfill{}':u'<span class="hfill"> </span>',
u'\\hspace*{\\fill}':u'', u'\\hspace*{}':u'', u'\\hspace{}':u'',
u'\\negthinspace{}':u'', u'\\qquad{}':u'  ', u'\\quad{}':u'',
u'\\space{}':u' ', u'\\thinspace{}':u'', u'~':u' ',
quotes = {
u'ald':u'»', u'als':u'', u'ard':u'«', u'ars':u'', u'eld':u'',
u'els':u'', u'erd':u'', u'ers':u'', u'fld':u'«', u'fls':u'',
u'frd':u'»', u'frs':u'', u'gld':u'', u'gls':u'', u'grd':u'',
u'grs':u'', u'pld':u'', u'pls':u'', u'prd':u'', u'prs':u'',
u'sld':u'', u'srd':u'',
referenceformats = {
u'eqref':u'(@↕)', u'pageref':u'#↕', u'ref':u'@↕',
u'vpageref':u'on-page#↕', u'vref':u'@on-page#↕',
size = {
vspaces = {
u'bigskip':u'<div class="bigskip"> </div>',
u'defskip':u'<div class="defskip"> </div>',
u'medskip':u'<div class="medskip"> </div>',
u'smallskip':u'<div class="smallskip"> </div>',
u'vfill':u'<div class="vfill"> </div>',
class TOCConfig(object):
"Configuration class from config file"
extractplain = {
u'cloned':[u'',], u'extracted':[u'',],
extracttitle = {
class TagConfig(object):
"Configuration class from config file"
barred = {
family = {
u'sans':u'span class="sans"', u'typewriter':u'tt',
flex = {
u'CharStyle:Code':u'span class="code"',
u'CharStyle:MenuItem':u'span class="menuitem"',
u'Code':u'span class="code"', u'MenuItem':u'span class="menuitem"',
u'Noun':u'span class="noun"', u'Strong':u'span class="strong"',
group = {
layouts = {
u'Center':u'div', u'Chapter':u'h?', u'Date':u'h2', u'Paragraph':u'div',
u'Part':u'h1', u'Quotation':u'blockquote', u'Quote':u'blockquote',
u'Section':u'h?', u'Subsection':u'h?', u'Subsubsection':u'h?',
listitems = {
u'Enumerate':u'ol', u'Itemize':u'ul',
notes = {
u'Comment':u'', u'Greyedout':u'span class="greyedout"', u'Note':u'',
shaped = {
u'italic':u'i', u'slanted':u'i', u'smallcaps':u'span class="versalitas"',
class TranslationConfig(object):
"Configuration class from config file"
constants = {
u'Appendix':u'Appendix', u'Book':u'Book', u'Chapter':u'Chapter',
u'Paragraph':u'Paragraph', u'Part':u'Part', u'Section':u'Section',
u'Subsection':u'Subsection', u'Subsubsection':u'Subsubsection',
u'abstract':u'Abstract', u'bibliography':u'Bibliography',
u'figure':u'figure', u'float-algorithm':u'Algorithm ',
u'float-figure':u'Figure ', u'float-listing':u'Listing ',
u'float-table':u'Table ', u'float-tableau':u'Tableau ',
u'footnotes':u'Footnotes', u'generated-by':u'Document generated by ',
u'generated-on':u' on ', u'index':u'Index',
u'jsmath-enable':u'Please enable JavaScript on your browser.',
u'jsmath-requires':u' requires JavaScript to correctly process the mathematics on this page. ',
u'jsmath-warning':u'Warning: ', u'list-algorithm':u'List of Algorithms',
u'list-figure':u'List of Figures', u'list-table':u'List of Tables',
u'list-tableau':u'List of Tableaux', u'main-page':u'Main page',
u'next':u'Next', u'nomenclature':u'Nomenclature',
u'on-page':u' on page ', u'prev':u'Previous',
u'references':u'References', u'toc':u'Table of Contents',
u'toc-for':u'Contents for ', u'up':u'Up',
languages = {
u'american':u'en', u'british':u'en', u'deutsch':u'de', u'dutch':u'nl',
u'english':u'en', u'french':u'fr', u'ngerman':u'de', u'spanish':u'es',
class CommandLineParser(object):
"A parser for runtime options"
def __init__(self, options):
self.options = options
def parseoptions(self, args):
"Parse command line options"
if len(args) == 0:
return None
while len(args) > 0 and args[0].startswith('--'):
key, value = self.readoption(args)
if not key:
return 'Option ' + value + ' not recognized'
if not value:
return 'Option ' + key + ' needs a value'
setattr(self.options, key, value)
return None
def readoption(self, args):
"Read the key and value for an option"
arg = args[0][2:]
del args[0]
if '=' in arg:
return self.readequals(arg, args)
key = arg.replace('-', '')
if not hasattr(self.options, key):
return None, key
current = getattr(self.options, key)
if isinstance(current, bool):
return key, True
# read value
if len(args) == 0:
return key, None
if args[0].startswith('"'):
initial = args[0]
del args[0]
return key, self.readquoted(args, initial)
value = args[0]
del args[0]
if isinstance(current, list):
return key, current
return key, value
def readquoted(self, args, initial):
"Read a value between quotes"
value = initial[1:]
while len(args) > 0 and not args[0].endswith('"') and not args[0].startswith('--'):
value += ' ' + args[0]
del args[0]
if len(args) == 0 or args[0].startswith('--'):
return None
value += ' ' + args[0:-1]
return value
def readequals(self, arg, args):
"Read a value with equals"
split = arg.split('=', 1)
key = split[0]
if not hasattr(self.options, key):
return None, key
value = split[1]
if not value.startswith('"'):
return key, value
return key, self.readquoted(args, value)
class Options(object):
"A set of runtime options"
instance = None
location = None
nocopy = False
copyright = False
debug = False
quiet = False
version = False
hardversion = False
versiondate = False
html = False
help = False
showlines = True
unicode = False
iso885915 = False
css = []
title = None
directory = None
destdirectory = None
toc = False
toctarget = ''
forceformat = None
lyxformat = False
target = None
splitpart = None
memory = True
lowmem = False
nobib = False
converter = 'imagemagick'
raw = False
jsmath = None
mathjax = None
nofooter = False
template = None
noconvert = False
notoclabels = False
letterfoot = True
numberfoot = False
symbolfoot = False
hoverfoot = True
marginfoot = False
endfoot = False
supfoot = True
alignfoot = False
footnotes = None
imageformat = None
copyimages = False
embedcss = []
# DCB : Add some stuff for syntax highlighting
defaultbrush = None
branches = dict()
def parseoptions(self, args):
"Parse command line options"
Options.location = args[0]
del args[0]
parser = CommandLineParser(Options)
result = parser.parseoptions(args)
if result:
if Options.version:
if Options.hardversion:
if Options.versiondate:
if Options.lyxformat:
if Options.splitpart:
Options.splitpart = int(Options.splitpart)
if Options.splitpart <= 0:
Trace.error('--splitpart requires a number bigger than zero')
Trace.error('--splitpart needs a numeric argument, not ' + Options.splitpart)
if Options.lowmem or Options.toc:
Options.memory = False
if Options.forceformat and not Options.imageformat:
Options.imageformat = Options.forceformat
if Options.imageformat == 'copy':
Options.copyimages = True
if Options.css == []:
Options.css = ['']
# set in Trace if necessary
for param in dir(Options):
if hasattr(Trace, param + 'mode'):
setattr(Trace, param + 'mode', getattr(self, param))
def usage(self):
"Show correct usage"
Trace.error('Usage: ' + os.path.basename(Options.location) + ' [options] [filein] [fileout]')
Trace.error('Convert LyX input file "filein" to HTML file "fileout".')
Trace.error('If filein (or fileout) is not given use standard input (or output).')
Trace.error('Main program of the eLyXer package (')
def parsefootnotes(self):
"Parse footnotes options."
if not Options.footnotes:
Options.marginfoot = False
Options.letterfoot = False
options = Options.footnotes.split(',')
for option in options:
footoption = option + 'foot'
if hasattr(Options, footoption):
setattr(Options, footoption, True)
Trace.error('Unknown footnotes option: ' + option)
if not Options.endfoot and not Options.marginfoot and not Options.hoverfoot:
Options.hoverfoot = True
if not Options.numberfoot and not Options.symbolfoot:
Options.letterfoot = True
def showoptions(self):
"Show all possible options"
Trace.error(' Common options:')
Trace.error(' --help: show this online help')
Trace.error(' --quiet: disables all runtime messages')
Trace.error(' Advanced options:')
Trace.error(' --debug: enable debugging messages (for developers)')
Trace.error(' --version: show version number and release date')
Trace.error(' --lyxformat: return the highest LyX version supported')
Trace.error(' Options for HTML output:')
Trace.error(' --title "title": set the generated page title')
Trace.error(' --css "file.css": use a custom CSS file')
Trace.error(' --embedcss "file.css": embed styles from a CSS file into the output')
Trace.error(' --html: output HTML 4.0 instead of the default XHTML')
Trace.error(' --unicode: full Unicode output')
Trace.error(' --iso885915: output a document with ISO-8859-15 encoding')
Trace.error(' --nofooter: remove the footer "generated by eLyXer"')
Trace.error(' --defaultbrush: the default SyntaxHighlighter brush to use for listings')
Trace.error(' Options for image output:')
Trace.error(' --directory "img_dir": look for images in the specified directory')
Trace.error(' --destdirectory "dest": put converted images into this directory')
Trace.error(' --imageformat ".ext": image output format, or "copy" to copy images')
Trace.error(' --noconvert: do not convert images, use in original locations')
Trace.error(' --converter "inkscape": use an alternative program to convert images')
Trace.error(' Options for footnote display:')
Trace.error(' --numberfoot: mark footnotes with numbers instead of letters')
Trace.error(' --symbolfoot: mark footnotes with symbols (*, **...)')
Trace.error(' --hoverfoot: show footnotes as hovering text (default)')
Trace.error(' --marginfoot: show footnotes with numbers instead of letters')
Trace.error(' --endfoot: show footnotes at the end of the page')
Trace.error(' --supfoot: use superscript for footnote markers (default)')
Trace.error(' --alignfoot: use aligned text for footnote markers')
Trace.error(' --footnotes "options": specify several comma-separated footnotes options')
Trace.error(' Available options are: "number", "symbol", "hover", "margin", "end",')
Trace.error(' "sup", "align"')
Trace.error(' Advanced output options:')
Trace.error(' --splitpart "depth": split the resulting webpage at the given depth')
Trace.error(' --toc: create a table of contents')
Trace.error(' --target "frame": make all links point to the given frame')
Trace.error(' --toctarget "page": generate a TOC that points to the given page')
Trace.error(' --notoclabels: omit the part labels in the TOC, such as Chapter')
Trace.error(' --lowmem: do the conversion on the fly (conserve memory)')
Trace.error(' --raw: generate HTML without header or footer.')
Trace.error(' --jsmath "URL": use jsMath from the given URL to display equations')
Trace.error(' --mathjax "URL": use MathJax from the given URL to display equations')
Trace.error(' --template "file": use a template, put everything in <!--$content-->')
Trace.error(' --copyright: add a copyright notice at the bottom')
Trace.error(' --nocopy (deprecated): no effect, maintained for backwards compatibility')
def showversion(self):
"Return the current eLyXer version string"
string = 'eLyXer version ' + GeneralConfig.version['number']
string += ' (' + GeneralConfig.version['date'] + ')'
def showhardversion(self):
"Return just the version string"
def showversiondate(self):
"Return just the version dte"
def showlyxformat(self):
"Return just the lyxformat parameter"
class BranchOptions(object):
"A set of options for a branch"
def __init__(self, name): = name
self.options = {'color':'#ffffff'}
def set(self, key, value):
"Set a branch option"
if not key.startswith(ContainerConfig.string['startcommand']):
Trace.error('Invalid branch option ' + key)
key = key.replace(ContainerConfig.string['startcommand'], '')
self.options[key] = value
def isselected(self):
"Return if the branch is selected"
if not 'selected' in self.options:
return False
return self.options['selected'] == '1'
def __unicode__(self):
"String representation"
return 'options for ' + + ': ' + unicode(self.options)
import gettext
class DocumentParameters(object):
"Global parameters for the document."
pdftitle = None
indentstandard = False
tocdepth = 10
startinglevel = 0
maxdepth = 10
language = None
bibliography = None
outputchanges = False
displaymode = False
class Translator(object):
"Reads the configuration file and tries to find a translation."
"Otherwise falls back to the messages in the config file."
instance = None
def translate(cls, key):
"Get the translated message for a key."
return cls.instance.getmessage(key)
translate = classmethod(translate)
def __init__(self):
self.translation = None
self.first = True
def findtranslation(self):
"Find the translation for the document language."
self.langcodes = None
if not DocumentParameters.language:
Trace.error('No language in document')
if not DocumentParameters.language in TranslationConfig.languages:
Trace.error('Unknown language ' + DocumentParameters.language)
if TranslationConfig.languages[DocumentParameters.language] == 'en':
langcodes = [TranslationConfig.languages[DocumentParameters.language]]
self.translation = gettext.translation('elyxer', None, langcodes)
except IOError:
Trace.error('No translation for ' + unicode(langcodes))
def getmessage(self, key):
"Get the translated message for the given key."
if self.first:
self.first = False
message = self.getuntranslated(key)
if not self.translation:
return message
message = self.translation.ugettext(message)
except IOError:
return message
def getuntranslated(self, key):
"Get the untranslated message."
if not key in TranslationConfig.constants:
Trace.error('Cannot translate ' + key)
return key
return TranslationConfig.constants[key]
Translator.instance = Translator()
class NumberCounter(object):
"A counter for numbers (by default)."
"The type can be changed to return letters, roman numbers..."
name = None
value = None
mode = None
master = None
symbols = NumberingConfig.sequence['symbols']
romannumerals = [
('M', 1000), ('CM', 900), ('D', 500), ('CD', 400), ('C', 100),
('XC', 90), ('L', 50), ('XL', 40), ('X', 10), ('IX', 9), ('V', 5),
('IV', 4), ('I', 1)
def __init__(self, name):
"Give a name to the counter." = name
def setmode(self, mode):
"Set the counter mode. Can be changed at runtime."
self.mode = mode
return self
def init(self, value):
"Set an initial value."
self.value = value
def increase(self):
"Increase the counter value and return the counter."
if not self.value:
self.value = 0
self.value += 1
return self
def gettext(self):
"Get the next value as a text string."
return unicode(self.value)
def getletter(self):
"Get the next value as a letter."
return self.getsequence(self.letters)
def getsymbol(self):
"Get the next value as a symbol."
return self.getsequence(self.symbols)
def getsequence(self, sequence):
"Get the next value from a sequence."
return sequence[(self.value - 1) % len(sequence)]
def getroman(self):
"Get the next value as a roman number."
result = ''
number = self.value
for numeral, value in self.romannumerals:
if number >= value:
result += numeral * (number / value)
number = number % value
return result
def getvalue(self):
"Get the current value as configured in the current mode."
if not self.mode or self.mode in ['text', '1']:
return self.gettext()
if self.mode == 'A':
return self.getletter()
if self.mode == 'a':
return self.getletter().lower()
if self.mode == 'I':
return self.getroman()
if self.mode == '*':
return self.getsymbol()
Trace.error('Unknown counter mode ' + self.mode)
return self.gettext()
def getnext(self):
"Get the next value as configured: increase() and getvalue()."
return self.increase().getvalue()
def reset(self):
"Reset the counter."
self.value = 0
def __unicode__(self):
"Return a printable representation."
result = 'Counter ' +
if self.mode:
result += ' in mode ' + self.mode
return result
class DependentCounter(NumberCounter):
"A counter which depends on another one (the master)."
def setmaster(self, master):
"Set the master counter."
self.master = master
self.last = self.master.getvalue()
return self
def increase(self):
"Increase or, if the master counter has changed, restart."
if self.last != self.master.getvalue():
self.last = self.master.getvalue()
return self
def getvalue(self):
"Get the value of the combined counter: master.dependent."
return self.master.getvalue() + '.' + NumberCounter.getvalue(self)
class NumberGenerator(object):
"A number generator for unique sequences and hierarchical structures. Used in:"
" * ordered part numbers: Chapter 3, Section 5.3."
" * unique part numbers: Footnote 15, Bibliography cite [15]."
" * chaptered part numbers: Figure 3.15, Equation (8.3)."
" * unique roman part numbers: Part I, Book IV."
chaptered = None
generator = None
romanlayouts = [x.lower() for x in NumberingConfig.layouts['roman']]
orderedlayouts = [x.lower() for x in NumberingConfig.layouts['ordered']]
counters = dict()
appendix = None
def deasterisk(self, type):
"Remove the possible asterisk in a layout type."
return type.replace('*', '')
def isunique(self, type):
"Find out if the layout type corresponds to a unique part."
return self.isroman(type)
def isroman(self, type):
"Find out if the layout type should have roman numeration."
return self.deasterisk(type).lower() in self.romanlayouts
def isinordered(self, type):
"Find out if the layout type corresponds to an (un)ordered part."
return self.deasterisk(type).lower() in self.orderedlayouts
def isnumbered(self, type):
"Find out if the type for a layout corresponds to a numbered layout."
if '*' in type:
return False
if self.isroman(type):
return True
if not self.isinordered(type):
return False
if self.getlevel(type) > DocumentParameters.maxdepth:
return False
return True
def isunordered(self, type):
"Find out if the type contains an asterisk, basically."
return '*' in type
def getlevel(self, type):
"Get the level that corresponds to a layout type."
if self.isunique(type):
return 0
if not self.isinordered(type):
Trace.error('Unknown layout type ' + type)
return 0
type = self.deasterisk(type).lower()
level = self.orderedlayouts.index(type) + 1
return level - DocumentParameters.startinglevel
def getparttype(self, type):
"Obtain the type for the part: without the asterisk, "
"and switched to Appendix if necessary."
if NumberGenerator.appendix and self.getlevel(type) == 1:
return 'Appendix'
return self.deasterisk(type)
def generate(self, type):
"Generate a number for a layout type."
"Unique part types such as Part or Book generate roman numbers: Part I."
"Ordered part types return dot-separated tuples: Chapter 5, Subsection 2.3.5."
"Everything else generates unique numbers: Bibliography [1]."
"Each invocation results in a new number."
return self.getcounter(type).getnext()
def getcounter(self, type):
"Get the counter for the given type."
type = type.lower()
if not type in self.counters:
self.counters[type] = self.create(type)
return self.counters[type]
def create(self, type):
"Create a counter for the given type."
if self.isnumbered(type) and self.getlevel(type) > 1:
index = self.orderedlayouts.index(type)
above = self.orderedlayouts[index - 1]
master = self.getcounter(above)
return self.createdependent(type, master)
counter = NumberCounter(type)
if self.isroman(type):
return counter
def getdependentcounter(self, type, master):
"Get (or create) a counter of the given type that depends on another."
if not type in self.counters or not self.counters[type].master:
self.counters[type] = self.createdependent(type, master)
return self.counters[type]
def createdependent(self, type, master):
"Create a dependent counter given the master."
return DependentCounter(type).setmaster(master)
def startappendix(self):
"Start appendices here."
firsttype = self.orderedlayouts[DocumentParameters.startinglevel]
counter = self.getcounter(firsttype)
NumberGenerator.appendix = True
class ChapteredGenerator(NumberGenerator):
"Generate chaptered numbers, as in Chapter.Number."
"Used in equations, figures: Equation (5.3), figure 8.15."
def generate(self, type):
"Generate a number which goes with first-level numbers (chapters). "
"For the article classes a unique number is generated."
if DocumentParameters.startinglevel > 0:
return NumberGenerator.generator.generate(type)
chapter = self.getcounter('Chapter')
return self.getdependentcounter(type, chapter).getnext()
NumberGenerator.chaptered = ChapteredGenerator()
NumberGenerator.generator = NumberGenerator()
class Parser(object):
"A generic parser"
def __init__(self):
self.begin = 0
self.parameters = dict()
def parseheader(self, reader):
"Parse the header"
header = reader.currentline().split()
self.begin = reader.linenumber
return header
def parseparameter(self, reader):
"Parse a parameter"
if reader.currentline().strip().startswith('<'):
key, value = self.parsexml(reader)
self.parameters[key] = value
split = reader.currentline().strip().split(' ', 1)
if len(split) == 0:
key = split[0]
if len(split) == 1:
self.parameters[key] = True
if not '"' in split[1]:
self.parameters[key] = split[1].strip()
doublesplit = split[1].split('"')
self.parameters[key] = doublesplit[1]
def parsexml(self, reader):
"Parse a parameter in xml form: <param attr1=value...>"
strip = reader.currentline().strip()
if not strip.endswith('>'):
Trace.error('XML parameter ' + strip + ' should be <...>')
split = strip[1:-1].split()
if len(split) == 0:
Trace.error('Empty XML parameter <>')
return None, None
key = split[0]
del split[0]
if len(split) == 0:
return key, dict()
attrs = dict()
for attr in split:
if not '=' in attr:
Trace.error('Erroneous attribute for ' + key + ': ' + attr)
attr += '="0"'
parts = attr.split('=')
attrkey = parts[0]
value = parts[1].split('"')[1]
attrs[attrkey] = value
return key, attrs
def parseending(self, reader, process):
"Parse until the current ending is found"
if not self.ending:
Trace.error('No ending for ' + unicode(self))
while not reader.currentline().startswith(self.ending):
def parsecontainer(self, reader, contents):
container = self.factory.createcontainer(reader)
if container:
container.parent = self.parent
def __unicode__(self):
"Return a description"
return self.__class__.__name__ + ' (' + unicode(self.begin) + ')'
class LoneCommand(Parser):
"A parser for just one command line"
def parse(self,reader):
"Read nothing"
return []
class TextParser(Parser):
"A parser for a command and a bit of text"
stack = []
def __init__(self, container):
self.ending = None
if container.__class__.__name__ in ContainerConfig.endings:
self.ending = ContainerConfig.endings[container.__class__.__name__]
self.endings = []
def parse(self, reader):
"Parse lines as long as they are text"
self.endings = TextParser.stack + [ContainerConfig.endings['Layout'],
ContainerConfig.endings['Inset'], self.ending]
contents = []
while not self.isending(reader):
self.parsecontainer(reader, contents)
return contents
def isending(self, reader):
"Check if text is ending"
current = reader.currentline().split()
if len(current) == 0:
return False
if current[0] in self.endings:
if current[0] in TextParser.stack:
TextParser.stack = []
return True
return False
class ExcludingParser(Parser):
"A parser that excludes the final line"
def parse(self, reader):
"Parse everything up to (and excluding) the final line"
contents = []
self.parseending(reader, lambda: self.parsecontainer(reader, contents))
return contents
class BoundedParser(ExcludingParser):
"A parser bound by a final line"
def parse(self, reader):
"Parse everything, including the final line"
contents = ExcludingParser.parse(self, reader)
# skip last line
return contents
class BoundedDummy(Parser):
"A bound parser that ignores everything"
def parse(self, reader):
"Parse the contents of the container"
self.parseending(reader, lambda: reader.nextline())
# skip last line
return []
class StringParser(Parser):
"Parses just a string"
def parseheader(self, reader):
"Do nothing, just take note"
self.begin = reader.linenumber + 1
return []
def parse(self, reader):
"Parse a single line"
contents = reader.currentline()
return contents
class InsetParser(BoundedParser):
"Parses a LyX inset"
def parse(self, reader):
"Parse inset parameters into a dictionary"
startcommand = ContainerConfig.string['startcommand']
while reader.currentline() != '' and not reader.currentline().startswith(startcommand):
return BoundedParser.parse(self, reader)
class ContainerOutput(object):
"The generic HTML output for a container."
def gethtml(self, container):
"Show an error."
Trace.error('gethtml() not implemented for ' + unicode(self))
def isempty(self):
"Decide if the output is empty: by default, not empty."
return False
class EmptyOutput(ContainerOutput):
def gethtml(self, container):
"Return empty HTML code."
return []
def isempty(self):
"This output is particularly empty."
return True
class FixedOutput(ContainerOutput):
"Fixed output"
def gethtml(self, container):
"Return constant HTML code"
return container.html
class ContentsOutput(ContainerOutput):
"Outputs the contents converted to HTML"
def gethtml(self, container):
"Return the HTML code"
html = []
if container.contents == None:
return html
for element in container.contents:
if not hasattr(element, 'gethtml'):
Trace.error('No html in ' + element.__class__.__name__ + ': ' + unicode(element))
return html
html += element.gethtml()
return html
class TaggedOutput(ContentsOutput):
"Outputs an HTML tag surrounding the contents."
tag = None
breaklines = False
empty = False
def settag(self, tag, breaklines=False, empty=False):
"Set the value for the tag and other attributes."
self.tag = tag
if breaklines:
self.breaklines = breaklines
if empty:
self.empty = empty
return self
def setbreaklines(self, breaklines):
"Set the value for breaklines."
self.breaklines = breaklines
return self
def gethtml(self, container):
"Return the HTML code."
if self.empty:
return [self.selfclosing(container)]
html = []
html += ContentsOutput.gethtml(self, container)
return html
def open(self, container):
"Get opening line."
if not self.checktag():
return ''
open = '<' + self.tag + '>'
if self.breaklines:
return open + '\n'
return open
def close(self, container):
"Get closing line."
if not self.checktag():
return ''
close = '</' + self.tag.split()[0] + '>'
if self.breaklines:
return '\n' + close + '\n'
return close
def selfclosing(self, container):
"Get self-closing line."
if not self.checktag():
return ''
selfclosing = '<' + self.tag + '/>'
if self.breaklines:
return selfclosing + '\n'
return selfclosing
def checktag(self):
"Check that the tag is valid."
if not self.tag:
Trace.error('No tag in ' + unicode(container))
return False
if self.tag == '':
return False
return True
class FilteredOutput(ContentsOutput):
"Returns the output in the contents, but filtered:"
"some strings are replaced by others."
def __init__(self):
"Initialize the filters."
self.filters = []
def addfilter(self, original, replacement):
"Add a new filter: replace the original by the replacement."
self.filters.append((original, replacement))
def gethtml(self, container):
"Return the HTML code"
result = []
html = ContentsOutput.gethtml(self, container)
for line in html:
return result
def filter(self, line):
"Filter a single line with all available filters."
for original, replacement in self.filters:
if original in line:
line = line.replace(original, replacement)
return line
class StringOutput(ContainerOutput):
"Returns a bare string as output"
def gethtml(self, container):
"Return a bare string"
return [container.string]
class Cloner(object):
"An object used to clone other objects."
def clone(cls, original):
"Return an exact copy of an object."
"The original object must have an empty constructor."
return cls.create(original.__class__)
def create(cls, type):
"Create an object of a given class."
clone = type.__new__(type)
return clone
clone = classmethod(clone)
create = classmethod(create)
class ContainerExtractor(object):
"A class to extract certain containers."
def __init__(self, config):
"The config parameter is a map containing three lists: allowed, copied and extracted."
"Each of the three is a list of class names for containers."
"Allowed containers are included as is into the result."
"Cloned containers are cloned and placed into the result."
"Extracted containers are looked into."
"All other containers are silently ignored."
self.allowed = config['allowed']
self.cloned = config['cloned']
self.extracted = config['extracted']
def extract(self, container):
"Extract a group of selected containers from a container."
list = []
locate = lambda c: c.__class__.__name__ in self.allowed + self.cloned
recursive = lambda c: c.__class__.__name__ in self.extracted
process = lambda c: self.process(c, list)
container.recursivesearch(locate, recursive, process)
return list
def process(self, container, list):
"Add allowed containers, clone cloned containers and add the clone."
name = container.__class__.__name__
if name in self.allowed:
elif name in self.cloned:
Trace.error('Unknown container class ' + name)
def safeclone(self, container):
"Return a new container with contents only in a safe list, recursively."
clone = Cloner.clone(container)
clone.output = container.output
clone.contents = self.extract(container)
return clone
class Position(object):
"A position in a text to parse"
def __init__(self):
self.endinglist = EndingList()
def checkbytemark(self):
"Check for a Unicode byte mark and skip it."
if self.finished():
if ord(self.current()) == 0xfeff:
def skip(self, string):
"Skip a string"
Trace.error('Unimplemented skip()')
def identifier(self):
"Return an identifier for the current position."
Trace.error('Unimplemented identifier()')
return 'Error'
def isout(self):
"Find out if we are out of the position yet."
Trace.error('Unimplemented isout()')
return True
def current(self):
"Return the current character"
Trace.error('Unimplemented current()')
return ''
def extract(self, length):
"Extract the next string of the given length, or None if not enough text."
Trace.error('Unimplemented extract()')
return None
def checkfor(self, string):
"Check for a string at the given position."
return string == self.extract(len(string))
def checkforlower(self, string):
"Check for a string in lower case."
extracted = self.extract(len(string))
if not extracted:
return False
return string.lower() == self.extract(len(string)).lower()
def finished(self):
"Find out if the current formula has finished"
if self.isout():
return True
return self.endinglist.checkin(self)
def skipcurrent(self):
"Return the current character and skip it."
current = self.current()
return current
def next(self):
"Advance the position and return the next character."
return self.current()
def checkskip(self, string):
"Check for a string at the given position; if there, skip it"
if not self.checkfor(string):
return False
return True
def glob(self, currentcheck):
"Glob a bit of text that satisfies a check"
glob = ''
while not self.finished() and currentcheck(self.current()):
glob += self.current()
return glob
def globalpha(self):
"Glob a bit of alpha text"
return self.glob(lambda current: current.isalpha())
def globnumber(self):
"Glob a row of digits."
return self.glob(lambda current: current.isdigit())
def checkidentifier(self):
"Check if the current character belongs to an identifier."
return self.isidentifier(self.current())
def isidentifier(self, char):
"Return if the given character is alphanumeric or _."
if char.isalnum() or char == '_':
return True
return False
def globidentifier(self):
"Glob alphanumeric and _ symbols."
return self.glob(lambda current: self.isidentifier(current))
def skipspace(self):
"Skip all whitespace at current position"
return self.glob(lambda current: current.isspace())
def globincluding(self, magicchar):
"Glob a bit of text up to (including) the magic char."
glob = self.glob(lambda current: current != magicchar) + magicchar
return glob
def globexcluding(self, magicchar):
"Glob a bit of text up until (excluding) the magic char."
return self.glob(lambda current: current != magicchar)
def pushending(self, ending, optional = False):
"Push a new ending to the bottom"
self.endinglist.add(ending, optional)
def popending(self, expected = None):
"Pop the ending found at the current position"
ending = self.endinglist.pop(self)
if expected and expected != ending:
Trace.error('Expected ending ' + expected + ', got ' + ending)
return ending
def error(self, message):
"Show an error message and the position identifier."
Trace.error(message + ': ' + self.identifier())
class TextPosition(Position):
"A parse position based on a raw text."
def __init__(self, text):
"Create the position from some text."
self.pos = 0
self.text = text
def skip(self, string):
"Skip a string of characters."
self.pos += len(string)
def identifier(self):
"Return a sample of the remaining text."
length = 30
if self.pos + length > len(self.text):
length = len(self.text) - self.pos - 1
return '*' + self.text[self.pos:self.pos + length]
def isout(self):
"Find out if we are out of the text yet."
return self.pos >= len(self.text)
def current(self):
"Return the current character, assuming we are not out."
return self.text[self.pos]
def extract(self, length):
"Extract the next string of the given length, or None if not enough text."
if self.pos + length > len(self.text):
return None
return self.text[self.pos : self.pos + length]
class FilePosition(Position):
"A parse position based on an underlying file."
def __init__(self, filename):
"Create the position from a file."
self.reader = LineReader(filename)
self.number = 1
self.pos = 0
def skip(self, string):
"Skip a string of characters."
length = len(string)
while self.pos + length > len(self.reader.currentline()):
length -= len(self.reader.currentline()) - self.pos + 1
self.pos += length
def nextline(self):
"Go to the next line."
self.number += 1
self.pos = 0
def identifier(self):
"Return the current line and line number in the file."
before = self.reader.currentline()[:self.pos - 1]
after = self.reader.currentline()[self.pos:]
return 'line ' + unicode(self.number) + ': ' + before + '*' + after
def isout(self):
"Find out if we are out of the text yet."
if self.pos > len(self.reader.currentline()):
if self.pos > len(self.reader.currentline()) + 1:
Trace.error('Out of the line ' + self.reader.currentline() + ': ' + unicode(self.pos))
return self.reader.finished()
def current(self):
"Return the current character, assuming we are not out."
if self.pos == len(self.reader.currentline()):
return '\n'
if self.pos > len(self.reader.currentline()):
Trace.error('Out of the line ' + self.reader.currentline() + ': ' + unicode(self.pos))
return '*'
return self.reader.currentline()[self.pos]
def extract(self, length):
"Extract the next string of the given length, or None if not enough text."
if self.pos + length > len(self.reader.currentline()):
return None
return self.reader.currentline()[self.pos : self.pos + length]
class EndingList(object):
"A list of position endings"
def __init__(self):
self.endings = []
def add(self, ending, optional):
"Add a new ending to the list"
self.endings.append(PositionEnding(ending, optional))
def checkin(self, pos):
"Search for an ending"
if self.findending(pos):
return True
return False
def pop(self, pos):
"Remove the ending at the current position"
if pos.isout():
Trace.error('No ending out of bounds')
return ''
ending = self.findending(pos)
if not ending:
Trace.error('No ending at ' + pos.current())
return ''
for each in reversed(self.endings):
if each == ending:
return each.ending
elif not each.optional:
Trace.error('Removed non-optional ending ' + each)
Trace.error('No endings left')
return ''
def findending(self, pos):
"Find the ending at the current position"
if len(self.endings) == 0:
return None
for index, ending in enumerate(reversed(self.endings)):
if ending.checkin(pos):
return ending
if not ending.optional:
return None
return None
def checkpending(self):
"Check if there are any pending endings"
if len(self.endings) != 0:
Trace.error('Pending ' + unicode(self) + ' left open')
def __unicode__(self):
"Printable representation"
string = 'endings ['
for ending in self.endings:
string += unicode(ending) + ','
if len(self.endings) > 0:
string = string[:-1]
return string + ']'
class PositionEnding(object):
"An ending for a parsing position"
def __init__(self, ending, optional):
self.ending = ending
self.optional = optional
def checkin(self, pos):
"Check for the ending"
return pos.checkfor(self.ending)
def __unicode__(self):
"Printable representation"
string = 'Ending ' + self.ending
if self.optional:
string += ' (optional)'
return string
class Container(object):
"A container for text and objects in a lyx file"
partkey = None
parent = None
begin = None
def __init__(self):
self.contents = list()
def process(self):
"Process contents"
def gethtml(self):
"Get the resulting HTML"
html = self.output.gethtml(self)
if isinstance(html, basestring):
Trace.error('Raw string ' + html)
html = [html]
return self.escapeall(html)
def escapeall(self, lines):
"Escape all lines in an array according to the output options."
result = []
for line in lines:
if Options.html:
line = self.escape(line, EscapeConfig.html)
if Options.iso885915:
line = self.escape(line, EscapeConfig.iso885915)
line = self.escapeentities(line)
elif not Options.unicode:
line = self.escape(line, EscapeConfig.nonunicode)
return result
def escape(self, line, replacements = EscapeConfig.entities):
"Escape a line with replacements from a map"
pieces = replacements.keys()
# do them in order
for piece in pieces:
if piece in line:
line = line.replace(piece, replacements[piece])
return line
def escapeentities(self, line):
"Escape all Unicode characters to HTML entities."
result = ''
pos = TextPosition(line)
while not pos.finished():
if ord(pos.current()) > 128:
codepoint = hex(ord(pos.current()))
if codepoint == '0xd835':
codepoint = hex(ord( + 0xf800)
result += '&#' + codepoint[1:] + ';'
result += pos.current()
return result
def searchall(self, type):
"Search for all embedded containers of a given type"
list = []
self.searchprocess(type, lambda container: list.append(container))
return list
def searchremove(self, type):
"Search for all containers of a type and remove them"
list = self.searchall(type)
for container in list:
return list
def searchprocess(self, type, process):
"Search for elements of a given type and process them"
self.locateprocess(lambda container: isinstance(container, type), process)
def locateprocess(self, locate, process):
"Search for all embedded containers and process them"
for container in self.contents:
container.locateprocess(locate, process)
if locate(container):
def recursivesearch(self, locate, recursive, process):
"Perform a recursive search in the container."
for container in self.contents:
if recursive(container):
container.recursivesearch(locate, recursive, process)
if locate(container):
def extracttext(self):
"Extract all text from allowed containers."
result = ''
constants = ContainerExtractor(ContainerConfig.extracttext).extract(self)
for constant in constants:
result += constant.string
return result
def group(self, index, group, isingroup):
"Group some adjoining elements into a group"
if index >= len(self.contents):
if hasattr(self.contents[index], 'grouped'):
while index < len(self.contents) and isingroup(self.contents[index]):
self.contents[index].grouped = True
self.contents.insert(index, group)
def remove(self, index):
"Remove a container but leave its contents"
container = self.contents[index]
while len(container.contents) > 0:
self.contents.insert(index, container.contents.pop())
def tree(self, level = 0):
"Show in a tree"
Trace.debug(" " * level + unicode(self))
for container in self.contents:
container.tree(level + 1)
def getparameter(self, name):
"Get the value of a parameter, if present."
if not name in self.parameters:
return None
return self.parameters[name]
def getparameterlist(self, name):
"Get the value of a comma-separated parameter as a list."
paramtext = self.getparameter(name)
if not paramtext:
return []
return paramtext.split(',')
def hasemptyoutput(self):
"Check if the parent's output is empty."
current = self.parent
while current:
if current.output.isempty():
return True
current = current.parent
return False
def __unicode__(self):
"Get a description"
if not self.begin:
return self.__class__.__name__
return self.__class__.__name__ + '@' + unicode(self.begin)
class BlackBox(Container):
"A container that does not output anything"
def __init__(self):
self.parser = LoneCommand()
self.output = EmptyOutput()
self.contents = []
class LyXFormat(BlackBox):
"Read the lyxformat command"
def process(self):
"Show warning if version < 276"
version = int(self.header[1])
if version < 276:
Trace.error('Warning: unsupported old format version ' + str(version))
if version > int(GeneralConfig.version['lyxformat']):
Trace.error('Warning: unsupported new format version ' + str(version))
class StringContainer(Container):
"A container for a single string"
parsed = None
def __init__(self):
self.parser = StringParser()
self.output = StringOutput()
self.string = ''
def process(self):
"Replace special chars from the contents."
if self.parsed:
self.string = self.replacespecial(self.parsed)
self.parsed = None
def replacespecial(self, line):
"Replace all special chars from a line"
replaced = self.escape(line, EscapeConfig.entities)
replaced = self.changeline(replaced)
if ContainerConfig.string['startcommand'] in replaced and len(replaced) > 1:
# unprocessed commands
if self.begin:
message = 'Unknown command at ' + unicode(self.begin) + ': '
message = 'Unknown command: '
Trace.error(message + replaced.strip())
return replaced
def changeline(self, line):
line = self.escape(line, EscapeConfig.chars)
if not ContainerConfig.string['startcommand'] in line:
return line
line = self.escape(line, EscapeConfig.commands)
return line
def extracttext(self):
"Return all text."
return self.string
def __unicode__(self):
"Return a printable representation."
result = 'StringContainer'
if self.begin:
result += '@' + unicode(self.begin)
ellipsis = '...'
if len(self.string.strip()) <= 15:
ellipsis = ''
return result + ' (' + self.string.strip()[:15] + ellipsis + ')'
class Constant(StringContainer):
"A constant string"
def __init__(self, text):
self.contents = []
self.string = text
self.output = StringOutput()
def __unicode__(self):
return 'Constant: ' + self.string
class TaggedText(Container):
"Text inside a tag"
output = None
def __init__(self):
self.parser = TextParser(self)
self.output = TaggedOutput()
def complete(self, contents, tag, breaklines=False):
"Complete the tagged text and return it"
self.contents = contents
self.output.tag = tag
self.output.breaklines = breaklines
return self
def constant(self, text, tag, breaklines=False):
"Complete the tagged text with a constant"
constant = Constant(text)
return self.complete([constant], tag, breaklines)
def __unicode__(self):
"Return a printable representation."
if not hasattr(self.output, 'tag'):
return 'Emtpy tagged text'
if not self.output.tag:
return 'Tagged <unknown tag>'
return 'Tagged <' + self.output.tag + '>'
class ContainerSize(object):
"The size of a container."
width = None
height = None
maxwidth = None
maxheight = None
scale = None
def set(self, width = None, height = None):
"Set the proper size with width and height."
self.setvalue('width', width)
self.setvalue('height', height)
return self
def setmax(self, maxwidth = None, maxheight = None):
"Set max width and/or height."
self.setvalue('maxwidth', maxwidth)
self.setvalue('maxheight', maxheight)
return self
def readparameters(self, container):
"Read some size parameters off a container."
self.setparameter(container, 'width')
self.setparameter(container, 'height')
self.setparameter(container, 'scale')
return self
def setparameter(self, container, name):
"Read a size parameter off a container, and set it if present."
value = container.getparameter(name)
self.setvalue(name, value)
def setvalue(self, name, value):
"Set the value of a parameter name, only if it's valid."
value = self.processparameter(value)
if value:
setattr(self, name, value)