]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_1.py
1c7ca482d838fc2f4bb74c6827802a502d4465f7
[lyx.git] / lib / lyx2lyx / lyx_2_1.py
1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # -*- coding: utf-8 -*-
4 # Copyright (C) 2011 The LyX team
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
20 """ Convert files to the file format generated by lyx 2.1"""
21
22 import re, string
23 import unicodedata
24 import sys, os
25
26 # Uncomment only what you need to import, please.
27
28 from parser_tools import count_pars_in_inset, del_token, find_token, find_token_exact, \
29     find_token_backwards, find_end_of, find_end_of_inset, find_end_of_layout, \
30     find_end_of_sequence, find_re, get_option_value, get_containing_layout, \
31     get_value, get_quoted_value, set_option_value
32
33 #from parser_tools import find_token, find_end_of, find_tokens, \
34   #find_end_of_inset, find_end_of_layout, \
35   #is_in_inset, del_token, check_token
36
37 from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, get_ert
38
39 #from lyx2lyx_tools import insert_to_preamble, \
40 #  lyx2latex, latex_length, revert_flex_inset, \
41 #  revert_font_attrs, hex2ratio, str2bool
42
43 ####################################################################
44 # Private helper functions
45
46 #def remove_option(lines, m, option):
47     #''' removes option from line m. returns whether we did anything '''
48     #l = lines[m].find(option)
49     #if l == -1:
50         #return False
51     #val = lines[m][l:].split('"')[1]
52     #lines[m] = lines[m][:l - 1] + lines[m][l+len(option + '="' + val + '"'):]
53     #return True
54
55
56 ###############################################################################
57 ###
58 ### Conversion and reversion routines
59 ###
60 ###############################################################################
61
62 def revert_visible_space(document):
63     "Revert InsetSpace visible into its ERT counterpart"
64     i = 0
65     while True:
66       i = find_token(document.body, "\\begin_inset space \\textvisiblespace{}", i)
67       if i == -1:
68         return
69       end = find_end_of_inset(document.body, i)
70       subst = put_cmd_in_ert("\\textvisiblespace{}")
71       document.body[i:end + 1] = subst
72
73
74 def convert_undertilde(document):
75     " Load undertilde automatically "
76     i = find_token(document.header, "\\use_mathdots" , 0)
77     if i == -1:
78         i = find_token(document.header, "\\use_mhchem" , 0)
79     if i == -1:
80         i = find_token(document.header, "\\use_esint" , 0)
81     if i == -1:
82         document.warning("Malformed LyX document: Can't find \\use_mathdots.")
83         return;
84     j = find_token(document.preamble, "\\usepackage{undertilde}", 0)
85     if j == -1:
86         document.header.insert(i + 1, "\\use_undertilde 0")
87     else:
88         document.header.insert(i + 1, "\\use_undertilde 2")
89         del document.preamble[j]
90
91
92 def revert_undertilde(document):
93     " Load undertilde if used in the document "
94     undertilde = find_token(document.header, "\\use_undertilde" , 0)
95     if undertilde == -1:
96       document.warning("No \\use_undertilde line. Assuming auto.")
97     else:
98       val = get_value(document.header, "\\use_undertilde", undertilde)
99       del document.header[undertilde]
100       try:
101         usetilde = int(val)
102       except:
103         document.warning("Invalid \\use_undertilde value: " + val + ". Assuming auto.")
104         # probably usedots has not been changed, but be safe.
105         usetilde = 1
106
107       if usetilde == 0:
108         # do not load case
109         return
110       if usetilde == 2:
111         # force load case
112         add_to_preamble(document, ["\\usepackage{undertilde}"])
113         return
114
115     # so we are in the auto case. we want to load undertilde if \utilde is used.
116     i = 0
117     while True:
118       i = find_token(document.body, '\\begin_inset Formula', i)
119       if i == -1:
120         return
121       j = find_end_of_inset(document.body, i)
122       if j == -1:
123         document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
124         i += 1
125         continue
126       code = "\n".join(document.body[i:j])
127       if code.find("\\utilde") != -1:
128         add_to_preamble(document, ["\\@ifundefined{utilde}{\\usepackage{undertilde}}"])
129         return
130       i = j
131
132
133 def revert_negative_space(document):
134     "Revert InsetSpace negmedspace and negthickspace into its TeX-code counterpart"
135     i = 0
136     j = 0
137     reverted = False
138     while True:
139       i = find_token(document.body, "\\begin_inset space \\negmedspace{}", i)
140       if i == -1:
141         j = find_token(document.body, "\\begin_inset space \\negthickspace{}", j)
142         if j == -1:
143           # load amsmath in the preamble if not already loaded if we are at the end of checking
144           if reverted == True:
145             i = find_token(document.header, "\\use_amsmath 2", 0)
146             if i == -1:
147               add_to_preamble(document, ["\\@ifundefined{negthickspace}{\\usepackage{amsmath}}"])
148           return
149       if i == -1:
150         return
151       end = find_end_of_inset(document.body, i)
152       subst = put_cmd_in_ert("\\negmedspace{}")
153       document.body[i:end + 1] = subst
154       j = find_token(document.body, "\\begin_inset space \\negthickspace{}", j)
155       if j == -1:
156         return
157       end = find_end_of_inset(document.body, j)
158       subst = put_cmd_in_ert("\\negthickspace{}")
159       document.body[j:end + 1] = subst
160       reverted = True
161
162
163 def revert_math_spaces(document):
164     "Revert formulas with protected custom space and protected hfills to TeX-code"
165     i = 0
166     while True:
167       i = find_token(document.body, "\\begin_inset Formula", i)
168       if i == -1:
169         return
170       j = document.body[i].find("\\hspace*")
171       if j != -1:
172         end = find_end_of_inset(document.body, i)
173         subst = put_cmd_in_ert(document.body[i][21:])
174         document.body[i:end + 1] = subst
175       i = i + 1
176
177
178 def convert_japanese_encodings(document):
179     " Rename the japanese encodings to names understood by platex "
180     jap_enc_dict = {
181         "EUC-JP-pLaTeX": "euc",
182         "JIS-pLaTeX":    "jis",
183         "SJIS-pLaTeX":   "sjis"
184     }
185     i = find_token(document.header, "\\inputencoding" , 0)
186     if i == -1:
187         return
188     val = get_value(document.header, "\\inputencoding", i)
189     if val in jap_enc_dict.keys():
190         document.header[i] = "\\inputencoding %s" % jap_enc_dict[val]
191
192
193 def revert_japanese_encodings(document):
194     " Revert the japanese encodings name changes "
195     jap_enc_dict = {
196         "euc":  "EUC-JP-pLaTeX",
197         "jis":  "JIS-pLaTeX",
198         "sjis": "SJIS-pLaTeX"
199     }
200     i = find_token(document.header, "\\inputencoding" , 0)
201     if i == -1:
202         return
203     val = get_value(document.header, "\\inputencoding", i)
204     if val in jap_enc_dict.keys():
205         document.header[i] = "\\inputencoding %s" % jap_enc_dict[val]
206
207
208 def revert_justification(document):
209     " Revert the \\justification buffer param"
210     if not del_token(document.header, '\\justification', 0):
211         document.warning("Malformed LyX document: Missing \\justification.")
212
213
214 def revert_australian(document):
215     "Set English language variants Australian and Newzealand to English" 
216
217     if document.language == "australian" or document.language == "newzealand": 
218         document.language = "english"
219         i = find_token(document.header, "\\language", 0) 
220         if i != -1: 
221             document.header[i] = "\\language english" 
222     j = 0 
223     while True: 
224         j = find_token(document.body, "\\lang australian", j) 
225         if j == -1:
226             j = find_token(document.body, "\\lang newzealand", 0)
227             if j == -1:
228                 return
229             else:
230                 document.body[j] = document.body[j].replace("\\lang newzealand", "\\lang english")
231         else:
232             document.body[j] = document.body[j].replace("\\lang australian", "\\lang english") 
233         j += 1
234
235
236 def convert_biblio_style(document):
237     "Add a sensible default for \\biblio_style based on the citation engine."
238     i = find_token(document.header, "\\cite_engine", 0)
239     if i != -1:
240         engine = get_value(document.header, "\\cite_engine", i).split("_")[0]
241         style = {"basic": "plain", "natbib": "plainnat", "jurabib": "jurabib"}
242         document.header.insert(i + 1, "\\biblio_style " + style[engine])
243
244
245 def revert_biblio_style(document):
246     "BibTeX insets with default option use the style defined by \\biblio_style."
247     i = find_token(document.header, "\\biblio_style" , 0)
248     if i == -1:
249         document.warning("No \\biblio_style line. Nothing to do.")
250         return
251
252     default_style = get_value(document.header, "\\biblio_style", i)
253     del document.header[i]
254
255     # We are looking for bibtex insets having the default option
256     i = 0
257     while True:
258         i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
259         if i == -1:
260             return
261         j = find_end_of_inset(document.body, i)
262         if j == -1:
263             document.warning("Malformed LyX document: Can't find end of bibtex inset at line " + str(i))
264             i += 1
265             return
266         k = find_token(document.body, "options", i, j)
267         if k != -1:
268             options = get_quoted_value(document.body, "options", k)
269             if "default" in options.split(","):
270                 document.body[k] = 'options "%s"' \
271                     % options.replace("default", default_style)
272         i = j
273
274
275 def handle_longtable_captions(document, forward):
276     begin_table = 0
277     while True:
278         begin_table = find_token(document.body, '<lyxtabular version=', begin_table)
279         if begin_table == -1:
280             break
281         end_table = find_end_of(document.body, begin_table, '<lyxtabular', '</lyxtabular>')
282         if end_table == -1:
283             document.warning("Malformed LyX document: Could not find end of table.")
284             begin_table += 1
285             continue
286         fline = find_token(document.body, "<features", begin_table, end_table)
287         if fline == -1:
288             document.warning("Can't find features for inset at line " + str(begin_table))
289             begin_table += 1
290             continue
291         p = document.body[fline].find("islongtable")
292         if p == -1:
293             # no longtable
294             begin_table += 1
295             continue
296         numrows = get_option_value(document.body[begin_table], "rows")
297         try:
298             numrows = int(numrows)
299         except:
300             document.warning(document.body[begin_table])
301             document.warning("Unable to determine rows!")
302             begin_table = end_table
303             continue
304         begin_row = begin_table
305         for row in range(numrows):
306             begin_row = find_token(document.body, '<row', begin_row, end_table)
307             if begin_row == -1:
308                 document.warning("Can't find row " + str(row + 1))
309                 break
310             end_row = find_end_of(document.body, begin_row, '<row', '</row>')
311             if end_row == -1:
312                 document.warning("Can't find end of row " + str(row + 1))
313                 break
314             if forward:
315                 if (get_option_value(document.body[begin_row], 'caption') == 'true' and
316                     get_option_value(document.body[begin_row], 'endfirsthead') != 'true' and
317                     get_option_value(document.body[begin_row], 'endhead') != 'true' and
318                     get_option_value(document.body[begin_row], 'endfoot') != 'true' and
319                     get_option_value(document.body[begin_row], 'endlastfoot') != 'true'):
320                     document.body[begin_row] = set_option_value(document.body[begin_row], 'caption', 'true", endfirsthead="true')
321             elif get_option_value(document.body[begin_row], 'caption') == 'true':
322                 if get_option_value(document.body[begin_row], 'endfirsthead') == 'true':
323                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endfirsthead', 'false')
324                 if get_option_value(document.body[begin_row], 'endhead') == 'true':
325                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endhead', 'false')
326                 if get_option_value(document.body[begin_row], 'endfoot') == 'true':
327                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endfoot', 'false')
328                 if get_option_value(document.body[begin_row], 'endlastfoot') == 'true':
329                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endlastfoot', 'false')
330             begin_row = end_row
331         # since there could be a tabular inside this one, we 
332         # cannot jump to end.
333         begin_table += 1
334
335
336 def convert_longtable_captions(document):
337     "Add a firsthead flag to caption rows"
338     handle_longtable_captions(document, True)
339
340
341 def revert_longtable_captions(document):
342     "remove head/foot flag from caption rows"
343     handle_longtable_captions(document, False)
344
345
346 def convert_use_packages(document):
347     "use_xxx yyy => use_package xxx yyy"
348     packages = ["amsmath", "esint", "mathdots", "mhchem", "undertilde"]
349     for p in packages:
350         i = find_token(document.header, "\\use_%s" % p, 0)
351         if i != -1:
352             value = get_value(document.header, "\\use_%s" % p, i)
353             document.header[i] = "\\use_package %s %s" % (p, value)
354
355
356 def revert_use_packages(document):
357     "use_package xxx yyy => use_xxx yyy"
358     packages = ["amsmath", "esint", "mathdots", "mhchem", "undertilde"]
359     # the order is arbitrary for the use_package version, and not all packages need to be given.
360     # Ensure a complete list and correct order (important for older LyX versions and especially lyx2lyx)
361     j = 0
362     for p in packages:
363         regexp = re.compile(r'(\\use_package\s+%s)' % p)
364         i = find_re(document.header, regexp, j)
365         if i != -1:
366             value = get_value(document.header, "\\use_package %s" % p, i).split()[1]
367             del document.header[i]
368             j = i
369             document.header.insert(j, "\\use_%s %s"  % (p, value))
370         j = j + 1
371
372
373 def convert_use_mathtools(document):
374     "insert use_package mathtools"
375     i = find_token(document.header, "\\use_package", 0)
376     if i == -1:
377         document.warning("Malformed LyX document: Can't find \\use_package.")
378         return;
379     j = find_token(document.preamble, "\\usepackage{mathtools}", 0)
380     if j == -1:
381         document.header.insert(i + 1, "\\use_package mathtools 0")
382     else:
383         document.header.insert(i + 1, "\\use_package mathtools 2")
384         del document.preamble[j]
385
386
387 def revert_use_mathtools(document):
388     "remove use_package mathtools"
389     regexp = re.compile(r'(\\use_package\s+mathtools)')
390     i = find_re(document.header, regexp, 0)
391     value = "1" # default is auto
392     if i != -1:
393         value = get_value(document.header, "\\use_package" , i).split()[1]
394         del document.header[i]
395     if value == "2": # on
396         add_to_preamble(document, ["\\usepackage{mathtools}"])
397     elif value == "1": # auto
398         commands = ["mathclap", "mathllap", "mathrlap", \
399                     "lgathered", "rgathered", "vcentcolon", "dblcolon", \
400                     "coloneqq", "Coloneqq", "coloneq", "Coloneq", "eqqcolon", \
401                     "Eqqcolon", "eqcolon", "Eqcolon", "colonapprox", \
402                     "Colonapprox", "colonsim", "Colonsim"]
403         i = 0
404         while True:
405             i = find_token(document.body, '\\begin_inset Formula', i)
406             if i == -1:
407                 return
408             j = find_end_of_inset(document.body, i)
409             if j == -1:
410                 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
411                 i += 1
412                 continue
413             code = "\n".join(document.body[i:j])
414             for c in commands:
415                 if code.find("\\%s" % c) != -1:
416                     add_to_preamble(document, ["\\usepackage{mathtools}"])
417                     return
418             i = j
419
420
421 def convert_use_stmaryrd(document):
422     "insert use_package stmaryrd"
423     i = find_token(document.header, "\\use_package", 0)
424     if i == -1:
425         document.warning("Malformed LyX document: Can't find \\use_package.")
426         return;
427     j = find_token(document.preamble, "\\usepackage{stmaryrd}", 0)
428     if j == -1:
429         document.header.insert(i + 1, "\\use_package stmaryrd 0")
430     else:
431         document.header.insert(i + 1, "\\use_package stmaryrd 2")
432         del document.preamble[j]
433
434
435 def revert_use_stmaryrd(document):
436     "remove use_package stmaryrd"
437     regexp = re.compile(r'(\\use_package\s+stmaryrd)')
438     i = find_re(document.header, regexp, 0)
439     value = "1" # default is auto
440     if i != -1:
441         value = get_value(document.header, "\\use_package" , i).split()[1]
442         del document.header[i]
443     if value == "2": # on
444         add_to_preamble(document, ["\\usepackage{stmaryrd}"])
445     elif value == "1": # auto
446         commands = ["shortleftarrow", "shortrightarrow", "shortuparrow", \
447                     "shortdownarrow", "Yup", "Ydown", "Yleft", "Yright", \
448                     "varcurlyvee", "varcurlywedge", "minuso", "baro", \
449                     "sslash", "bbslash", "moo", "varotimes", "varoast", \
450                     "varobar", "varodot", "varoslash", "varobslash", \
451                     "varocircle", "varoplus", "varominus", "boxast", \
452                     "boxbar", "boxslash", "boxbslash", "boxcircle", \
453                     "boxbox", "boxempty", "merge", "vartimes", \
454                     "fatsemi", "sswarrow", "ssearrow", "curlywedgeuparrow", \
455                     "curlywedgedownarrow", "fatslash", "fatbslash", "lbag", \
456                     "rbag", "varbigcirc", "leftrightarroweq", \
457                     "curlyveedownarrow", "curlyveeuparrow", "nnwarrow", \
458                     "nnearrow", "leftslice", "rightslice", "varolessthan", \
459                     "varogreaterthan", "varovee", "varowedge", "talloblong", \
460                     "interleave", "obar", "obslash", "olessthan", \
461                     "ogreaterthan", "ovee", "owedge", "oblong", "inplus", \
462                     "niplus", "nplus", "subsetplus", "supsetplus", \
463                     "subsetpluseq", "supsetpluseq", "Lbag", "Rbag", \
464                     "llbracket", "rrbracket", "llparenthesis", \
465                     "rrparenthesis", "binampersand", "bindnasrepma", \
466                     "trianglelefteqslant", "trianglerighteqslant", \
467                     "ntrianglelefteqslant", "ntrianglerighteqslant", \
468                     "llfloor", "rrfloor", "llceil", "rrceil", "arrownot", \
469                     "Arrownot", "Mapstochar", "mapsfromchar", "Mapsfromchar", \
470                     "leftrightarrowtriangle", "leftarrowtriangle", \
471                     "rightarrowtriangle", \
472                     "bigcurlyvee", "bigcurlywedge", "bigsqcap", "bigbox", \
473                     "bigparallel", "biginterleave", "bignplus", \
474                     "varcopyright", "longarrownot", "Longarrownot", \
475                     "Mapsto", "mapsfrom", "Mapsfrom" "Longmapsto", \
476                     "longmapsfrom", "Longmapsfrom"]
477         # commands provided by stmaryrd.sty but LyX uses other packages:
478         # boxdot lightning, bigtriangledown, bigtriangleup
479
480         i = 0
481         while True:
482             i = find_token(document.body, '\\begin_inset Formula', i)
483             if i == -1:
484                 return
485             j = find_end_of_inset(document.body, i)
486             if j == -1:
487                 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
488                 i += 1
489                 continue
490             code = "\n".join(document.body[i:j])
491             for c in commands:
492                 if code.find("\\%s" % c) != -1:
493                     add_to_preamble(document, ["\\usepackage{stmaryrd}"])
494                     return
495             i = j
496
497
498 def convert_use_stackrel(document):
499     "insert use_package stackrel"
500     i = find_token(document.header, "\\use_package", 0)
501     if i == -1:
502         document.warning("Malformed LyX document: Can't find \\use_package.")
503         return;
504     j = find_token(document.preamble, "\\usepackage{stackrel}", 0)
505     if j == -1:
506         document.header.insert(i + 1, "\\use_package stackrel 0")
507     else:
508         document.header.insert(i + 1, "\\use_package stackrel 2")
509         del document.preamble[j]
510
511
512 def revert_use_stackrel(document):
513     "remove use_package stackrel"
514     regexp = re.compile(r'(\\use_package\s+stackrel)')
515     i = find_re(document.header, regexp, 0)
516     value = "1" # default is auto
517     if i != -1:
518         value = get_value(document.header, "\\use_package" , i).split()[1]
519         del document.header[i]
520     if value == "2": # on
521         add_to_preamble(document, ["\\usepackage{stackrel}"])
522     elif value == "1": # auto
523         regcmd = re.compile(r'.*\\stackrel\s*\[')
524         i = 0
525         while True:
526             i = find_token(document.body, '\\begin_inset Formula', i)
527             if i == -1:
528                 return
529             j = find_end_of_inset(document.body, i)
530             if j == -1:
531                 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
532                 i += 1
533                 continue
534             code = "\n".join(document.body[i:j])
535             if regcmd.match(code):
536                 add_to_preamble(document, ["\\usepackage{stackrel}"])
537                 return
538             i = j
539
540
541 def convert_cite_engine_type(document):
542     "Determine the \\cite_engine_type from the citation engine."
543     i = find_token(document.header, "\\cite_engine", 0)
544     if i == -1:
545         return
546     engine = get_value(document.header, "\\cite_engine", i)
547     if "_" in engine:
548         engine, type = engine.split("_")
549     else:
550         type = {"basic": "numerical", "jurabib": "authoryear"}[engine]
551     document.header[i] = "\\cite_engine " + engine
552     document.header.insert(i + 1, "\\cite_engine_type " + type)
553
554
555 def revert_cite_engine_type(document):
556     "Natbib had the type appended with an underscore."
557     engine_type = "numerical"
558     i = find_token(document.header, "\\cite_engine_type" , 0)
559     if i == -1:
560         document.warning("No \\cite_engine_type line. Assuming numerical.")
561     else:
562         engine_type = get_value(document.header, "\\cite_engine_type", i)
563         del document.header[i]
564
565     # We are looking for the natbib citation engine
566     i = find_token(document.header, "\\cite_engine natbib", 0)
567     if i == -1:
568         return
569     document.header[i] = "\\cite_engine natbib_" + engine_type
570
571
572 def revert_cancel(document):
573     "add cancel to the preamble if necessary"
574     commands = ["cancelto", "cancel", "bcancel", "xcancel"]
575     i = 0
576     while True:
577         i = find_token(document.body, '\\begin_inset Formula', i)
578         if i == -1:
579             return
580         j = find_end_of_inset(document.body, i)
581         if j == -1:
582             document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
583             i += 1
584             continue
585         code = "\n".join(document.body[i:j])
586         for c in commands:
587             if code.find("\\%s" % c) != -1:
588                 add_to_preamble(document, ["\\usepackage{cancel}"])
589                 return
590         i = j
591
592
593 def revert_verbatim(document):
594     " Revert verbatim einvironments completely to TeX-code. "
595     i = 0
596     consecutive = False
597     subst_end = ['\end_layout', '', '\\begin_layout Plain Layout',
598                  '\end_layout', '',
599                  '\\begin_layout Plain Layout', '', '',
600                  '\\backslash', '',
601                  'end{verbatim}',
602                  '\\end_layout', '', '\\end_inset',
603                  '', '', '\\end_layout']
604     subst_begin = ['\\begin_layout Standard', '\\noindent',
605                    '\\begin_inset ERT', 'status collapsed', '',
606                    '\\begin_layout Plain Layout', '', '', '\\backslash',
607                    'begin{verbatim}',
608                    '\\end_layout', '', '\\begin_layout Plain Layout', '']
609     while 1:
610         i = find_token(document.body, "\\begin_layout Verbatim", i)
611         if i == -1:
612             return
613         j = find_end_of_layout(document.body, i)
614         if j == -1:
615             document.warning("Malformed lyx document: Can't find end of Verbatim layout")
616             i += 1
617             continue
618         # delete all line breaks insets (there are no other insets)
619         l = i
620         while 1:
621             n = find_token(document.body, "\\begin_inset Newline newline", l)
622             if n == -1:
623                 n = find_token(document.body, "\\begin_inset Newline linebreak", l)
624                 if n == -1:
625                     break
626             m = find_end_of_inset(document.body, n)
627             del(document.body[m:m+1])
628             document.body[n:n+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
629             l += 1
630             j += 1
631         # consecutive verbatim environments need to be connected
632         k = find_token(document.body, "\\begin_layout Verbatim", j)
633         if k == j + 2 and consecutive == False:
634             consecutive = True
635             document.body[j:j+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
636             document.body[i:i+1] = subst_begin
637             continue
638         if k == j + 2 and consecutive == True:
639             document.body[j:j+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
640             del(document.body[i:i+1])
641             continue
642         if k != j + 2 and consecutive == True:
643             document.body[j:j+1] = subst_end
644             # the next paragraph must not be indented
645             document.body[j+19:j+19] = ['\\noindent']
646             del(document.body[i:i+1])
647             consecutive = False
648             continue
649         else:
650             document.body[j:j+1] = subst_end
651             # the next paragraph must not be indented
652             document.body[j+19:j+19] = ['\\noindent']
653             document.body[i:i+1] = subst_begin
654
655
656 def revert_tipa(document):
657     " Revert native TIPA insets to mathed or ERT. "
658     i = 0
659     while 1:
660         i = find_token(document.body, "\\begin_inset IPA", i)
661         if i == -1:
662             return
663         j = find_end_of_inset(document.body, i)
664         if j == -1:
665             document.warning("Malformed lyx document: Can't find end of IPA inset")
666             i += 1
667             continue
668         Multipar = False
669         n = find_token(document.body, "\\begin_layout", i, j)
670         if n == -1:
671             document.warning("Malformed lyx document: IPA inset has no embedded layout")
672             i += 1
673             continue
674         m = find_end_of_layout(document.body, n)
675         if m == -1:
676             document.warning("Malformed lyx document: Can't find end of embedded layout")
677             i += 1
678             continue
679         content = document.body[n+1:m]
680         p = find_token(document.body, "\\begin_layout", m, j)
681         if p != -1 or len(content) > 1:
682             Multipar = True
683             content = document.body[i+1:j]
684         if Multipar:
685             # IPA insets with multiple pars need to be wrapped by \begin{IPA}...\end{IPA}
686             document.body[i:j+1] = ['\\end_layout', '', '\\begin_layout Standard'] + put_cmd_in_ert("\\begin{IPA}") + ['\\end_layout'] + content + ['\\begin_layout Standard'] + put_cmd_in_ert("\\end{IPA}")
687             add_to_preamble(document, ["\\usepackage{tipa,tipx}"])
688         else:
689             # single-par IPA insets can be reverted to mathed
690             document.body[i:j+1] = ["\\begin_inset Formula $\\text{\\textipa{" + content[0] + "}}$", "\\end_inset"]
691         i = j
692
693
694 def revert_cell_rotation(document):
695   "Revert cell rotations to TeX-code"
696
697   load_rotating = False
698   i = 0
699   try:
700     while True:
701       # first, let's find out if we need to do anything
702       i = find_token(document.body, '<cell ', i)
703       if i == -1:
704         return
705       j = document.body[i].find('rotate="')
706       if j != -1:
707         k = document.body[i].find('"', j + 8)
708         value = document.body[i][j + 8 : k]
709         if value == "0":
710           rgx = re.compile(r' rotate="[^"]+?"')
711           # remove rotate option
712           document.body[i] = rgx.sub('', document.body[i])
713         elif value == "90":
714           rgx = re.compile(r' rotate="[^"]+?"')
715           document.body[i] = rgx.sub('rotate="true"', document.body[i])
716         else:
717           rgx = re.compile(r' rotate="[^"]+?"')
718           load_rotating = True
719           # remove rotate option
720           document.body[i] = rgx.sub('', document.body[i])
721           # write ERT
722           document.body[i + 5 : i + 5] = \
723             put_cmd_in_ert("\\end{turn}")
724           document.body[i + 4 : i + 4] = \
725             put_cmd_in_ert("\\begin{turn}{" + value + "}")
726         
727       i += 1
728         
729   finally:
730     if load_rotating:
731       add_to_preamble(document, ["\\@ifundefined{turnbox}{\usepackage{rotating}}{}"])
732
733
734 def convert_cell_rotation(document):
735     'Convert cell rotation statements from "true" to "90"'
736
737     i = 0
738     while True:
739       # first, let's find out if we need to do anything
740       i = find_token(document.body, '<cell ', i)
741       if i == -1:
742         return
743       j = document.body[i].find('rotate="true"')
744       if j != -1:
745         rgx = re.compile(r'rotate="[^"]+?"')
746         # convert "true" to "90"
747         document.body[i] = rgx.sub('rotate="90"', document.body[i])
748         
749       i += 1
750
751
752 def revert_table_rotation(document):
753   "Revert table rotations to TeX-code"
754
755   load_rotating = False
756   i = 0
757   try:
758     while True:
759       # first, let's find out if we need to do anything
760       i = find_token(document.body, '<features ', i)
761       if i == -1:
762         return
763       j = document.body[i].find('rotate="')
764       if j != -1:
765         end_table = find_token(document.body, '</lyxtabular>', j)
766         k = document.body[i].find('"', j + 8)
767         value = document.body[i][j + 8 : k]
768         if value == "0":
769           rgx = re.compile(r' rotate="[^"]+?"')
770           # remove rotate option
771           document.body[i] = rgx.sub('', document.body[i])
772         elif value == "90":
773           rgx = re.compile(r'rotate="[^"]+?"')
774           document.body[i] = rgx.sub('rotate="true"', document.body[i])
775         else:
776           rgx = re.compile(r' rotate="[^"]+?"')
777           load_rotating = True
778           # remove rotate option
779           document.body[i] = rgx.sub('', document.body[i])
780           # write ERT
781           document.body[end_table + 3 : end_table + 3] = \
782             put_cmd_in_ert("\\end{turn}")
783           document.body[i - 2 : i - 2] = \
784             put_cmd_in_ert("\\begin{turn}{" + value + "}")
785         
786       i += 1
787         
788   finally:
789     if load_rotating:
790       add_to_preamble(document, ["\\@ifundefined{turnbox}{\usepackage{rotating}}{}"])
791
792
793 def convert_table_rotation(document):
794     'Convert table rotation statements from "true" to "90"'
795
796     i = 0
797     while True:
798       # first, let's find out if we need to do anything
799       i = find_token(document.body, '<features ', i)
800       if i == -1:
801         return
802       j = document.body[i].find('rotate="true"')
803       if j != -1:
804         rgx = re.compile(r'rotate="[^"]+?"')
805         # convert "true" to "90"
806         document.body[i] = rgx.sub('rotate="90"', document.body[i])
807         
808       i += 1
809
810
811 def convert_listoflistings(document):
812     'Convert ERT \lstlistoflistings to TOC lstlistoflistings inset'
813     # We can support roundtrip because the command is so simple
814     i = 0
815     while True:
816         i = find_token(document.body, "\\begin_inset ERT", i)
817         if i == -1:
818             return
819         j = find_end_of_inset(document.body, i)
820         if j == -1:
821             document.warning("Malformed lyx document: Can't find end of ERT inset")
822             i += 1
823             continue
824         ert = get_ert(document.body, i)
825         if ert == "\\lstlistoflistings{}":
826             document.body[i:j] = ["\\begin_inset CommandInset toc", "LatexCommand lstlistoflistings", ""]
827             i = i + 4
828         else:
829             i = j + 1
830
831
832 def revert_listoflistings(document):
833     'Convert TOC lstlistoflistings inset to ERT lstlistoflistings'
834     i = 0
835     while True:
836         i = find_token(document.body, "\\begin_inset CommandInset toc", i)
837         if i == -1:
838             return
839         if document.body[i+1] == "LatexCommand lstlistoflistings":
840             j = find_end_of_inset(document.body, i)
841             if j == -1:
842                 document.warning("Malformed lyx document: Can't find end of TOC inset")
843                 i += 1
844                 continue
845             subst = put_cmd_in_ert("\\lstlistoflistings{}")
846             document.body[i:j+1] = subst
847             add_to_preamble(document, ["\\usepackage{listings}"])
848         i = i + 1
849
850
851 def convert_use_amssymb(document):
852     "insert use_package amssymb"
853     regexp = re.compile(r'(\\use_package\s+amsmath)')
854     i = find_re(document.header, regexp, 0)
855     if i == -1:
856         document.warning("Malformed LyX document: Can't find \\use_package amsmath.")
857         return;
858     value = get_value(document.header, "\\use_package" , i).split()[1]
859     useamsmath = 0
860     try:
861         useamsmath = int(value)
862     except:
863         document.warning("Invalid \\use_package amsmath: " + value + ". Assuming auto.")
864         useamsmath = 1
865     j = find_token(document.preamble, "\\usepackage{amssymb}", 0)
866     if j == -1:
867         document.header.insert(i + 1, "\\use_package amssymb %d" % useamsmath)
868     else:
869         document.header.insert(i + 1, "\\use_package amssymb 2")
870         del document.preamble[j]
871
872
873 def revert_use_amssymb(document):
874     "remove use_package amssymb"
875     regexp1 = re.compile(r'(\\use_package\s+amsmath)')
876     regexp2 = re.compile(r'(\\use_package\s+amssymb)')
877     i = find_re(document.header, regexp1, 0)
878     j = find_re(document.header, regexp2, 0)
879     value1 = "1" # default is auto
880     value2 = "1" # default is auto
881     if i != -1:
882         value1 = get_value(document.header, "\\use_package" , i).split()[1]
883     if j != -1:
884         value2 = get_value(document.header, "\\use_package" , j).split()[1]
885         del document.header[j]
886     if value1 != value2 and value2 == "2": # on
887         add_to_preamble(document, ["\\usepackage{amssymb}"])
888
889
890 def revert_ancientgreek(document):
891     "Set the document language for ancientgreek to greek" 
892
893     if document.language == "ancientgreek": 
894         document.language = "greek"
895         i = find_token(document.header, "\\language", 0) 
896         if i != -1: 
897             document.header[i] = "\\language greek" 
898     j = 0 
899     while True: 
900         j = find_token(document.body, "\\lang ancientgreek", j) 
901         if j == -1:
902             return
903         else:
904             document.body[j] = document.body[j].replace("\\lang ancientgreek", "\\lang greek") 
905         j += 1
906
907
908 def revert_languages(document):
909     "Set the document language for new supported languages to English" 
910
911     languages = [
912                  "coptic", "divehi", "hindi", "kurmanji", "lao", "marathi", "occitan", "sanskrit",
913                  "syriac", "tamil", "telugu", "urdu"
914                 ]
915     for n in range(len(languages)):
916         if document.language == languages[n]:
917             document.language = "english"
918             i = find_token(document.header, "\\language", 0) 
919             if i != -1: 
920                 document.header[i] = "\\language english" 
921         j = 0
922         while j < len(document.body): 
923             j = find_token(document.body, "\\lang " + languages[n], j)
924             if j != -1:
925                 document.body[j] = document.body[j].replace("\\lang " + languages[n], "\\lang english")
926                 j += 1
927             else:
928                 j = len(document.body)
929
930
931 def convert_armenian(document):
932     "Use polyglossia and thus non-TeX fonts for Armenian" 
933
934     if document.language == "armenian": 
935         i = find_token(document.header, "\\use_non_tex_fonts", 0) 
936         if i != -1: 
937             document.header[i] = "\\use_non_tex_fonts true" 
938
939
940 def revert_armenian(document):
941     "Use ArmTeX and thus TeX fonts for Armenian" 
942
943     if document.language == "armenian": 
944         i = find_token(document.header, "\\use_non_tex_fonts", 0) 
945         if i != -1: 
946             document.header[i] = "\\use_non_tex_fonts false" 
947
948
949 def revert_libertine(document):
950     " Revert native libertine font definition to LaTeX " 
951
952     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
953         i = find_token(document.header, "\\font_roman libertine", 0)
954         if i != -1:
955             osf = False
956             j = find_token(document.header, "\\font_osf true", 0)
957             if j != -1:
958                 osf = True
959             preamble = "\\usepackage"
960             if osf:
961                 document.header[j] = "\\font_osf false"
962             else:
963                 preamble += "[lining]"
964             preamble += "{libertine-type1}"
965             add_to_preamble(document, [preamble])
966             document.header[i] = "\\font_roman default"
967
968
969 def revert_txtt(document):
970     " Revert native txtt font definition to LaTeX " 
971
972     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
973         i = find_token(document.header, "\\font_typewriter txtt", 0)
974         if i != -1:
975             preamble = "\\renewcommand{\\ttdefault}{txtt}"
976             add_to_preamble(document, [preamble])
977             document.header[i] = "\\font_typewriter default"
978
979
980 def revert_mathdesign(document):
981     " Revert native mathdesign font definition to LaTeX " 
982
983     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
984         mathdesign_dict = {
985         "mdbch":  "charter",
986         "mdput":  "utopia",
987         "mdugm":  "garamond"
988         }
989         i = find_token(document.header, "\\font_roman", 0)
990         if i == -1:
991             return
992         val = get_value(document.header, "\\font_roman", i)
993         if val in mathdesign_dict.keys():
994             preamble = "\\usepackage[%s" % mathdesign_dict[val]
995             expert = False
996             j = find_token(document.header, "\\font_osf true", 0)
997             if j != -1:
998                 expert = True
999                 document.header[j] = "\\font_osf false"
1000             l = find_token(document.header, "\\font_sc true", 0)
1001             if l != -1:
1002                 expert = True
1003                 document.header[l] = "\\font_sc false"
1004             if expert:
1005                 preamble += ",expert"
1006             preamble += "]{mathdesign}"
1007             add_to_preamble(document, [preamble])
1008             document.header[i] = "\\font_roman default"
1009
1010
1011 def revert_texgyre(document):
1012     " Revert native TeXGyre font definition to LaTeX " 
1013
1014     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1015         texgyre_fonts = ["tgadventor", "tgbonum", "tgchorus", "tgcursor", \
1016                          "tgheros", "tgpagella", "tgschola", "tgtermes"]
1017         i = find_token(document.header, "\\font_roman", 0)
1018         if i != -1:
1019             val = get_value(document.header, "\\font_roman", i)
1020             if val in texgyre_fonts:
1021                 preamble = "\\usepackage{%s}" % val
1022                 add_to_preamble(document, [preamble])
1023                 document.header[i] = "\\font_roman default"
1024         i = find_token(document.header, "\\font_sans", 0)
1025         if i != -1:
1026             val = get_value(document.header, "\\font_sans", i)
1027             if val in texgyre_fonts:
1028                 preamble = "\\usepackage{%s}" % val
1029                 add_to_preamble(document, [preamble])
1030                 document.header[i] = "\\font_sans default"
1031         i = find_token(document.header, "\\font_typewriter", 0)
1032         if i != -1:
1033             val = get_value(document.header, "\\font_typewriter", i)
1034             if val in texgyre_fonts:
1035                 preamble = "\\usepackage{%s}" % val
1036                 add_to_preamble(document, [preamble])
1037                 document.header[i] = "\\font_typewriter default"
1038
1039
1040 def revert_ipadeco(document):
1041     " Revert IPA decorations to ERT "
1042     i = 0
1043     while True:
1044       i = find_token(document.body, "\\begin_inset IPADeco", i)
1045       if i == -1:
1046           return
1047       end = find_end_of_inset(document.body, i)
1048       if end == -1:
1049           document.warning("Can't find end of inset at line " + str(i))
1050           i += 1
1051           continue
1052       line = document.body[i]
1053       rx = re.compile(r'\\begin_inset IPADeco (.*)$')
1054       m = rx.match(line)
1055       decotype = m.group(1)
1056       if decotype != "toptiebar" and decotype != "bottomtiebar":
1057           document.warning("Invalid IPADeco type: " + decotype)
1058           i = end
1059           continue
1060       blay = find_token(document.body, "\\begin_layout Plain Layout", i, end)
1061       if blay == -1:
1062           document.warning("Can't find layout for inset at line " + str(i))
1063           i = end
1064           continue
1065       bend = find_end_of_layout(document.body, blay)
1066       if bend == -1:
1067           document.warning("Malformed LyX document: Could not find end of IPADeco inset's layout.")
1068           i = end
1069           continue
1070       substi = ["\\begin_inset ERT", "status collapsed", "",
1071                 "\\begin_layout Plain Layout", "", "", "\\backslash", 
1072                 decotype + "{", "\\end_layout", "", "\\end_inset"]
1073       substj = ["\\size default", "", "\\begin_inset ERT", "status collapsed", "",
1074                 "\\begin_layout Plain Layout", "", "}", "\\end_layout", "", "\\end_inset"]
1075       # do the later one first so as not to mess up the numbering
1076       document.body[bend:end + 1] = substj
1077       document.body[i:blay + 1] = substi
1078       i = end + len(substi) + len(substj) - (end - bend) - (blay - i) - 2
1079       add_to_preamble(document, "\\usepackage{tipa}")
1080
1081
1082 def revert_ipachar(document):
1083     ' Revert \\IPAChar to ERT '
1084     i = 0
1085     found = False
1086     while i < len(document.body):
1087         m = re.match(r'(.*)\\IPAChar \\(\w+\{\w+\})(.*)', document.body[i])
1088         if m:
1089             found = True
1090             before = m.group(1)
1091             ipachar = m.group(2)
1092             after = m.group(3)
1093             subst = [before,
1094                      '\\begin_inset ERT',
1095                      'status collapsed', '',
1096                      '\\begin_layout Standard',
1097                      '', '', '\\backslash',
1098                      ipachar,
1099                      '\\end_layout', '',
1100                      '\\end_inset', '',
1101                      after]
1102             document.body[i: i+1] = subst
1103             i = i + len(subst)
1104         else:
1105             i = i + 1
1106     if found:
1107         add_to_preamble(document, "\\usepackage{tone}")
1108
1109
1110 def revert_minionpro(document):
1111     " Revert native MinionPro font definition to LaTeX " 
1112
1113     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1114         i = find_token(document.header, "\\font_roman minionpro", 0)
1115         if i != -1:
1116             osf = False
1117             j = find_token(document.header, "\\font_osf true", 0)
1118             if j != -1:
1119                 osf = True
1120             preamble = "\\usepackage"
1121             if osf:
1122                 document.header[j] = "\\font_osf false"
1123             else:
1124                 preamble += "[lf]"
1125             preamble += "{MinionPro}"
1126             add_to_preamble(document, [preamble])
1127             document.header[i] = "\\font_roman default"
1128
1129
1130 def revert_mathfonts(document):
1131     " Revert native math font definitions to LaTeX " 
1132
1133     i = find_token(document.header, "\\font_math", 0)
1134     if i == -1:
1135        return
1136     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1137         val = get_value(document.header, "\\font_math", i)
1138         if val == "eulervm":
1139             add_to_preamble(document, "\\usepackage{eulervm}")
1140         elif val == "default":
1141             mathfont_dict = {
1142             "lmodern":  "\\renewcommand{\\rmdefault}{lmr}",
1143             "minionpro":  "\\usepackage[onlytext,lf]{MinionPro}",
1144             "minionpro-osf":  "\\usepackage[onlytext]{MinionPro}",
1145             "palatino":  "\\renewcommand{\\rmdefault}{ppl}",
1146             "palatino-osf":  "\\renewcommand{\\rmdefault}{pplj}",
1147             "times":  "\\renewcommand{\\rmdefault}{ptm}",
1148             "utopia":  "\\renewcommand{\\rmdefault}{futs}",
1149             "utopia-osf":  "\\renewcommand{\\rmdefault}{futj}",
1150             }
1151             j = find_token(document.header, "\\font_roman", 0)
1152             if j != -1:
1153                 rm = get_value(document.header, "\\font_roman", j)
1154                 k = find_token(document.header, "\\font_osf true", 0)
1155                 if k != -1:
1156                     rm += "-osf"
1157                 if rm in mathfont_dict.keys():
1158                     add_to_preamble(document, mathfont_dict[rm])
1159                     document.header[j] = "\\font_roman default"
1160                     if k != -1:
1161                         document.header[k] = "\\font_osf false"
1162     del document.header[i]
1163
1164
1165 def revert_mdnomath(document):
1166     " Revert mathdesign and fourier without math " 
1167
1168     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1169         mathdesign_dict = {
1170         "md-charter": "mdbch",
1171         "md-utopia": "mdput",
1172         "md-garamond": "mdugm"
1173         }
1174         i = find_token(document.header, "\\font_roman", 0)
1175         if i == -1:
1176             return
1177         val = get_value(document.header, "\\font_roman", i)
1178         if val in mathdesign_dict.keys():
1179             j = find_token(document.header, "\\font_math", 0)
1180             if j == -1:
1181                 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1182             mval = get_value(document.header, "\\font_math", j)
1183             if mval == "default":
1184                 document.header[i] = "\\font_roman default"
1185                 add_to_preamble(document, "\\renewcommand{\\rmdefault}{%s}" % mathdesign_dict[val])
1186             else:
1187                 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1188
1189
1190 def convert_mdnomath(document):
1191     " Change mathdesign font name " 
1192
1193     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1194         mathdesign_dict = {
1195         "mdbch":  "md-charter",
1196         "mdput":  "md-utopia",
1197         "mdugm":  "md-garamond"
1198         }
1199         i = find_token(document.header, "\\font_roman", 0)
1200         if i == -1:
1201             return
1202         val = get_value(document.header, "\\font_roman", i)
1203         if val in mathdesign_dict.keys():
1204              document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1205
1206
1207 def revert_newtxmath(document):
1208     " Revert native newtxmath definitions to LaTeX " 
1209
1210     i = find_token(document.header, "\\font_math", 0)
1211     if i == -1:
1212        return
1213     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1214         val = get_value(document.header, "\\font_math", i)
1215         mathfont_dict = {
1216         "libertine-ntxm":  "\\usepackage[libertine]{newtxmath}",
1217         "minion-ntxm":  "\\usepackage[minion]{newtxmath}",
1218         "newtxmath":  "\\usepackage{newtxmath}",
1219         }
1220         if val in mathfont_dict.keys():
1221             add_to_preamble(document, mathfont_dict[val])
1222             document.header[i] = "\\font_math auto"
1223
1224
1225 def revert_biolinum(document):
1226     " Revert native biolinum font definition to LaTeX " 
1227
1228     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1229         i = find_token(document.header, "\\font_sans biolinum", 0)
1230         if i != -1:
1231             osf = False
1232             j = find_token(document.header, "\\font_osf true", 0)
1233             if j != -1:
1234                 osf = True
1235             preamble = "\\usepackage"
1236             if not osf:
1237                 preamble += "[lf]"
1238             preamble += "{biolinum-type1}"
1239             add_to_preamble(document, [preamble])
1240             document.header[i] = "\\font_sans default"
1241
1242
1243 def revert_uop(document):
1244     " Revert native URW Classico (Optima) font definition to LaTeX "
1245
1246     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1247         i = find_token(document.header, "\\font_sans uop", 0)
1248         if i != -1:
1249                 preamble = "\\renewcommand{\\sfdefault}{uop}"
1250                 add_to_preamble(document, [preamble])
1251                 document.header[i] = "\\font_sans default"
1252
1253
1254 def convert_latexargs(document):
1255     " Convert InsetArgument to new syntax "
1256
1257     if find_token(document.body, "\\begin_inset Argument", 0) == -1:
1258         # nothing to do.
1259         return
1260
1261     # A list of layouts (document classes) with only optional or no arguments.
1262     # These can be safely converted to the new syntax
1263     # (I took the liberty to add some of my personal layouts/modules here; JSP)
1264     safe_layouts = ["aa", "aapaper", "aastex", "achemso", "acmsiggraph", "AEA",
1265                     "agu-dtd", "agums", "agutex", "amsart", "amsbook", "apa",
1266                     "arab-article", "armenian-article", "article-beamer", "article",
1267                     "beamer", "book", "broadway", "chess", "cl2emult", "ctex-article",
1268                     "ctex-book", "ctex-report", "dinbrief", "docbook-book", "docbook-chapter",
1269                     "docbook", "docbook-section", "doublecol-new", "dtk", "ectaart", "egs",
1270                     "elsarticle", "elsart", "entcs", "europecv", "extarticle", "extbook",
1271                     "extletter", "extreport", "foils", "frletter", "g-brief2", "g-brief",
1272                     "heb-article", "heb-letter", "hollywood", "IEEEtran", "ijmpc", "ijmpd",
1273                     "iopart", "isprs", "jarticle", "jasatex", "jbook", "jgrga", "jreport",
1274                     "jsarticle", "jsbeamer", "jsbook", "jss", "kluwer", "latex8", "letter", "lettre",
1275                     "literate-article", "literate-book", "literate-report", "llncs", "ltugboat",
1276                     "memoir", "moderncv", "mwart", "mwbk", "mwrep", "paper", "powerdot",
1277                     "recipebook", "report", "revtex4", "revtex", "scrartcl", "scrarticle-beamer",
1278                     "scrbook", "scrlettr", "scrlttr2", "scrreprt", "seminar", "siamltex",
1279                     "sigplanconf", "simplecv", "singlecol", "singlecol-new", "slides", "spie",
1280                     "svglobal3", "svglobal", "svjog", "svmono", "svmult", "svprobth", "tarticle",
1281                     "tbook", "treport", "tufte-book", "tufte-handout"]
1282     # A list of "safe" modules, same as above
1283     safe_modules = ["biblatex", "beameraddons", "beamersession", "braille", "customHeadersFooters",
1284                     "endnotes", "enumitem", "eqs-within-sections", "figs-within-sections", "fix-cm",
1285                     "fixltx2e", "foottoend", "hanging", "jscharstyles", "knitr", "lilypond",
1286                     "linguistics", "linguisticx", "logicalmkup", "minimalistic", "nomindex", "noweb",
1287                     "pdfcomment", "sweave", "tabs-within-sections", "theorems-ams-bytype",
1288                     "theorems-ams-extended-bytype", "theorems-ams-extended", "theorems-ams", "theorems-bytype",
1289                     "theorems-chap-bytype", "theorems-chap", "theorems-named", "theorems-sec-bytype",
1290                     "theorems-sec", "theorems-starred", "theorems-std", "todonotes"]
1291     # Modules we need to take care of
1292     caveat_modules = ["initials"]
1293     # information about the relevant styles in caveat_modules (number of opt and req args)
1294     # use this if we get more caveat_modules. For now, use hard coding (see below).
1295     # initials = [{'Layout' : 'Initial', 'opt' : 1, 'req' : 1}]
1296
1297     # Is this a known safe layout?
1298     safe_layout = document.textclass in safe_layouts
1299     if not safe_layout:
1300         document.warning("Lyx2lyx knows nothing about textclass '%s'. "
1301                          "Please check if short title insets have been converted correctly."
1302                          % document.textclass)
1303     # Do we use unsafe or unknown modules
1304     mods = document.get_module_list()
1305     unknown_modules = False
1306     used_caveat_modules = list()
1307     for mod in mods:
1308         if mod in safe_modules:
1309             continue
1310         if mod in caveat_modules:
1311             used_caveat_modules.append(mod)
1312             continue
1313         unknown_modules = True
1314         document.warning("Lyx2lyx knows nothing about module '%s'. "
1315                          "Please check if short title insets have been converted correctly."
1316                          % mod)
1317
1318     i = 0
1319     while True:
1320         i = find_token(document.body, "\\begin_inset Argument", i)
1321         if i == -1:
1322             return
1323
1324         if not safe_layout or unknown_modules:
1325             # We cannot do more here since we have no access to this layout.
1326             # InsetArgument itself will do the real work
1327             # (see InsetArgument::updateBuffer())
1328             document.body[i] = "\\begin_inset Argument 999"
1329             i = i + 1
1330             continue
1331         
1332         # Find containing paragraph layout
1333         parent = get_containing_layout(document.body, i)
1334         if parent == False:
1335             document.warning("Malformed lyx document: Can't find parent paragraph layout")
1336             i = i + 1
1337             continue
1338         parbeg = parent[1]
1339         parend = parent[2]
1340         allowed_opts = -1
1341         first_req = -1
1342         if len(used_caveat_modules) > 0:
1343             # We know for now that this must be the initials module with the Initial layout
1344             # If we get more such modules, we need some automating.
1345             if parent[0] == "Initial":
1346                 # Layout has 1 opt and 1 req arg.
1347                 # Count the actual arguments
1348                 actualargs = 0
1349                 for p in range(parbeg, parend):
1350                     if document.body[p] == "\\begin_inset Argument":
1351                         actualargs += 1
1352                 if actualargs == 1:
1353                     allowed_opts = 0
1354                     first_req = 2
1355         # Collect all arguments in this paragraph
1356         argnr = 0
1357         for p in range(parbeg, parend):
1358             if document.body[p] == "\\begin_inset Argument":
1359                 argnr += 1
1360                 if allowed_opts != -1:
1361                     # We have less arguments than opt + required.
1362                     # required must take precedence.
1363                     if argnr > allowed_opts and argnr < first_req:
1364                         argnr = first_req
1365                 document.body[p] = "\\begin_inset Argument %d" % argnr
1366         i = i + 1
1367
1368
1369 def revert_latexargs(document):
1370     " Revert InsetArgument to old syntax "
1371
1372     i = 0
1373     rx = re.compile(r'^\\begin_inset Argument (\d+)$')
1374     args = dict()
1375     while True:
1376         # Search for Argument insets
1377         i = find_token(document.body, "\\begin_inset Argument", i)
1378         if i == -1:
1379             return
1380         m = rx.match(document.body[i])
1381         if not m:
1382             # No ID: inset already reverted
1383             i = i + 1
1384             continue
1385         # Find containing paragraph layout
1386         parent = get_containing_layout(document.body, i)
1387         if parent == False:
1388             document.warning("Malformed lyx document: Can't find parent paragraph layout")
1389             i = i + 1
1390             continue
1391         parbeg = parent[1]
1392         parend = parent[2]
1393         realparbeg = parent[3]
1394         # Collect all arguments in this paragraph 
1395         realparend = parend
1396         for p in range(parbeg, parend):
1397             m = rx.match(document.body[p])
1398             if m:
1399                 val = int(m.group(1))
1400                 j = find_end_of_inset(document.body, p)
1401                 # Revert to old syntax
1402                 document.body[p] = "\\begin_inset Argument"
1403                 if j == -1:
1404                     document.warning("Malformed lyx document: Can't find end of Argument inset")
1405                     continue
1406                 if val > 0:
1407                     args[val] = document.body[p : j + 1]
1408                 # Adjust range end
1409                 realparend = realparend - len(document.body[p : j + 1])
1410                 # Remove arg inset at this position
1411                 del document.body[p : j + 1]
1412             if p >= realparend:
1413                 break
1414         # Now sort the arg insets
1415         subst = [""]
1416         for f in sorted(args):
1417             subst += args[f]
1418             del args[f]
1419         # Insert the sorted arg insets at paragraph begin
1420         document.body[realparbeg : realparbeg] = subst
1421
1422         i = realparbeg + 1 + len(subst)
1423
1424
1425 def revert_Argument_to_TeX_brace(document, line, n, nmax, environment):
1426     '''
1427     Reverts an InsetArgument to TeX-code
1428     usage:
1429     revert_Argument_to_TeX_brace(document, LineOfBeginLayout, StartArgument, EndArgument, isEnvironment)
1430     LineOfBeginLayout is the line  of the \begin_layout statement
1431     StartArgument is the number of the first argument that needs to be converted
1432     EndArgument is the number of the last argument that needs to be converted or the last defined one
1433     isEnvironment must be true, if the layout id for a LaTeX environment
1434     '''
1435     lineArg = 0
1436     while lineArg != -1 and n < nmax + 1:
1437       lineArg = find_token(document.body, "\\begin_inset Argument " + str(n), line)
1438       if lineArg != -1:
1439         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
1440         # we have to assure that no other inset is in the Argument
1441         beginInset = find_token(document.body, "\\begin_inset", beginPlain)
1442         endInset = find_token(document.body, "\\end_inset", beginPlain)
1443         k = beginPlain + 1
1444         l = k
1445         while beginInset < endInset and beginInset != -1:
1446           beginInset = find_token(document.body, "\\begin_inset", k)
1447           endInset = find_token(document.body, "\\end_inset", l)
1448           k = beginInset + 1
1449           l = endInset + 1
1450         if environment == False:
1451           document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}{")
1452           del(document.body[lineArg : beginPlain + 1])
1453         else:
1454           document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}")
1455           document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("{")
1456         n = n + 1
1457
1458
1459 def convert_TeX_brace_to_Argument(document, line, n, nmax, inset, environment):
1460     '''
1461     Converts TeX code for mandatory arguments to an InsetArgument
1462     The conversion of TeX code for optional arguments must be done with another routine
1463     !!! Be careful if the braces are different in your case as expected here:
1464     - "}{" separates mandatory arguments of commands
1465     - "}" + "{" separates mandatory arguments of commands
1466     - "}" + " " + "{" separates mandatory arguments of commands
1467     - { and } surround a mandatory argument of an environment
1468     usage:
1469     convert_TeX_brace_to_Argument(document, LineOfBeginLayout/Inset, StartArgument, EndArgument, isInset, isEnvironment)
1470     LineOfBeginLayout/Inset is the line  of the \begin_layout or \begin_inset statement
1471     StartArgument is the number of the first ERT that needs to be converted
1472     EndArgument is the number of the last ERT that needs to be converted
1473     isInset must be true, if braces inside an InsetLayout needs to be converted
1474     isEnvironment must be true, if the layout is for a LaTeX environment
1475     
1476     Todo: this routine can currently handle only one mandatory argument of environments
1477     '''
1478     lineERT = line
1479     endn = line
1480     loop = 1
1481     while lineERT != -1 and n < nmax + 1:
1482       lineERT = find_token(document.body, "\\begin_inset ERT", lineERT)
1483       if environment == False and lineERT != -1:
1484         bracePair = find_token(document.body, "}{", lineERT)
1485         # assure that the "}{" is in this ERT
1486         if bracePair == lineERT + 5:
1487           end = find_token(document.body, "\\end_inset", bracePair)
1488           document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
1489           if loop == 1:
1490             # in the case that n > 1 we have optional arguments before
1491             # therefore detect them if any
1492             if n > 1:
1493               # first check if there is an argument
1494               lineArg = find_token(document.body, "\\begin_inset Argument", line)
1495               if lineArg < lineERT and lineArg != -1:
1496                 # we have an argument, so now search backwards for its end
1497                 # we must now assure that we don't find other insets like e.g. a newline
1498                 endInsetArg = lineERT
1499                 endLayoutArg = endInsetArg
1500                 while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
1501                   endInsetArg = endInsetArg - 1
1502                   endLayoutArg = endInsetArg
1503                   endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
1504                   endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
1505                 line = endInsetArg + 1
1506             if inset == False:
1507               document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1508             else:
1509               document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1510           else:
1511             document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1512           n = n + 1
1513           endn = end
1514           loop = loop + 1
1515         # now check the case that we have "}" + "{" in two ERTs
1516         else:
1517           endBrace = find_token(document.body, "}", lineERT)
1518           if endBrace == lineERT + 5:
1519             beginBrace = find_token(document.body, "{", endBrace)
1520             # assure that the ERTs are consecutive (11 or 12 depending if there is a space between the ERTs or not)
1521             if beginBrace == endBrace + 11 or beginBrace == endBrace + 12:
1522               end = find_token(document.body, "\\end_inset", beginBrace)
1523               document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
1524               if loop == 1:
1525                 # in the case that n > 1 we have optional arguments before
1526                 # therefore detect them if any
1527                 if n > 1:
1528                   # first check if there is an argument
1529                   lineArg = find_token(document.body, "\\begin_inset Argument", line)
1530                   if lineArg < lineERT and lineArg != -1:
1531                     # we have an argument, so now search backwards for its end
1532                     # we must now assure that we don't find other insets like e.g. a newline
1533                     endInsetArg = lineERT
1534                     endLayoutArg = endInsetArg
1535                     while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
1536                       endInsetArg = endInsetArg - 1
1537                       endLayoutArg = endInsetArg
1538                       endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
1539                       endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
1540                     line = endInsetArg + 1
1541                 if inset == False:
1542                   document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1543                 else:
1544                   document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1545               else:
1546                 document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1547               n = n + 1
1548               loop = loop + 1
1549               # set the line where the next argument will be inserted
1550               if beginBrace == endBrace + 11:
1551                 endn = end - 11
1552               else:
1553                 endn = end - 12
1554           else:
1555             lineERT = lineERT + 1
1556       if environment == True and lineERT != -1:
1557         opening = find_token(document.body, "{", lineERT)
1558         if opening == lineERT + 5: # assure that the "{" is in this ERT
1559           end = find_token(document.body, "\\end_inset", opening)
1560           document.body[lineERT : end + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1561           n = n + 1
1562           lineERT2 = find_token(document.body, "\\begin_inset ERT", lineERT)
1563           closing = find_token(document.body, "}", lineERT2)
1564           if closing == lineERT2 + 5: # assure that the "}" is in this ERT
1565             end2 = find_token(document.body, "\\end_inset", closing)
1566             document.body[lineERT2 : end2 + 1] = ["\\end_layout", "", "\\end_inset"]
1567         else:
1568           lineERT = lineERT + 1
1569
1570
1571 def revert_IEEEtran(document):
1572   '''
1573   Reverts InsetArgument of
1574   Page headings
1575   Biography
1576   Biography without photo
1577   to TeX-code
1578   '''
1579   if document.textclass == "IEEEtran":
1580     i = 0
1581     j = 0
1582     k = 0
1583     while True:
1584       if i != -1:
1585         i = find_token(document.body, "\\begin_layout Page headings", i)
1586       if i != -1:
1587         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1588         i = i + 1
1589       if j != -1:
1590         j = find_token(document.body, "\\begin_layout Biography without photo", j)
1591       if j != -1:
1592         revert_Argument_to_TeX_brace(document, j, 1, 1, True)
1593         j = j + 1
1594       if k != -1:
1595         k = find_token(document.body, "\\begin_layout Biography", k)
1596         kA = find_token(document.body, "\\begin_layout Biography without photo", k)
1597         if k == kA and k != -1:
1598           k = k + 1
1599           continue
1600       if k != -1:
1601         # start with the second argument, therefore 2
1602         revert_Argument_to_TeX_brace(document, k, 2, 2, True)
1603         k = k + 1
1604       if i == -1 and j == -1 and k == -1:
1605         return
1606
1607
1608 def convert_IEEEtran(document):
1609   '''
1610   Converts ERT of
1611   Page headings
1612   Biography
1613   Biography without photo
1614   to InsetArgument
1615   '''
1616   if document.textclass == "IEEEtran":
1617     i = 0
1618     j = 0
1619     k = 0
1620     while True:
1621       if i != -1:
1622         i = find_token(document.body, "\\begin_layout Page headings", i)
1623       if i != -1:
1624         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1625         i = i + 1
1626       if j != -1:
1627         j = find_token(document.body, "\\begin_layout Biography without photo", j)
1628       if j != -1:
1629         convert_TeX_brace_to_Argument(document, j, 1, 1, False, True)
1630         j = j + 1
1631       if k != -1:
1632         # assure that we don't handle Biography Biography without photo
1633         k = find_token(document.body, "\\begin_layout Biography", k)
1634         kA = find_token(document.body, "\\begin_layout Biography without photo", k - 1)
1635       if k == kA and k != -1:
1636         k = k + 1
1637         continue
1638       if k != -1:
1639         # the argument we want to convert is the second one
1640         convert_TeX_brace_to_Argument(document, k, 2, 2, False, True)
1641         k = k + 1
1642       if i == -1 and j == -1 and k == -1:
1643         return
1644
1645
1646 def revert_AASTeX(document):
1647   " Reverts InsetArgument of Altaffilation to TeX-code "
1648   if document.textclass == "aastex":
1649     i = 0
1650     while True:
1651       if i != -1:
1652         i = find_token(document.body, "\\begin_layout Altaffilation", i)
1653       if i != -1:
1654         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1655         i = i + 1
1656       if i == -1:
1657         return
1658
1659
1660 def convert_AASTeX(document):
1661   " Converts ERT of Altaffilation to InsetArgument "
1662   if document.textclass == "aastex":
1663     i = 0
1664     while True:
1665       if i != -1:
1666         i = find_token(document.body, "\\begin_layout Altaffilation", i)
1667       if i != -1:
1668         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1669         i = i + 1
1670       if i == -1:
1671         return
1672
1673
1674 def revert_AGUTeX(document):
1675   " Reverts InsetArgument of Author affiliation to TeX-code "
1676   if document.textclass == "agutex":
1677     i = 0
1678     while True:
1679       if i != -1:
1680         i = find_token(document.body, "\\begin_layout Author affiliation", i)
1681       if i != -1:
1682         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1683         i = i + 1
1684       if i == -1:
1685         return
1686
1687
1688 def convert_AGUTeX(document):
1689   " Converts ERT of Author affiliation to InsetArgument "
1690   if document.textclass == "agutex":
1691     i = 0
1692     while True:
1693       if i != -1:
1694         i = find_token(document.body, "\\begin_layout Author affiliation", i)
1695       if i != -1:
1696         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1697         i = i + 1
1698       if i == -1:
1699         return
1700
1701
1702 def revert_IJMP(document):
1703   " Reverts InsetArgument of MarkBoth to TeX-code "
1704   if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1705     i = 0
1706     while True:
1707       if i != -1:
1708         i = find_token(document.body, "\\begin_layout MarkBoth", i)
1709       if i != -1:
1710         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1711         i = i + 1
1712       if i == -1:
1713         return
1714
1715
1716 def convert_IJMP(document):
1717   " Converts ERT of MarkBoth to InsetArgument "
1718   if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1719     i = 0
1720     while True:
1721       if i != -1:
1722         i = find_token(document.body, "\\begin_layout MarkBoth", i)
1723       if i != -1:
1724         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1725         i = i + 1
1726       if i == -1:
1727         return
1728
1729
1730 def revert_SIGPLAN(document):
1731   " Reverts InsetArguments of SIGPLAN to TeX-code "
1732   if document.textclass == "sigplanconf":
1733     i = 0
1734     j = 0
1735     while True:
1736       if i != -1:
1737         i = find_token(document.body, "\\begin_layout Conference", i)
1738       if i != -1:
1739         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1740         i = i + 1
1741       if j != -1:
1742         j = find_token(document.body, "\\begin_layout Author", j)
1743       if j != -1:
1744         revert_Argument_to_TeX_brace(document, j, 1, 2, False)
1745         j = j + 1
1746       if i == -1 and j == -1:
1747         return
1748
1749
1750 def convert_SIGPLAN(document):
1751   " Converts ERT of SIGPLAN to InsetArgument "
1752   if document.textclass == "sigplanconf":
1753     i = 0
1754     j = 0
1755     while True:
1756       if i != -1:
1757         i = find_token(document.body, "\\begin_layout Conference", i)
1758       if i != -1:
1759         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1760         i = i + 1
1761       if j != -1:
1762         j = find_token(document.body, "\\begin_layout Author", j)
1763       if j != -1:
1764         convert_TeX_brace_to_Argument(document, j, 1, 2, False, False)
1765         j = j + 1
1766       if i == -1 and j == -1:
1767         return
1768
1769
1770 def revert_SIGGRAPH(document):
1771   " Reverts InsetArgument of Flex CRcat to TeX-code "
1772   if document.textclass == "acmsiggraph":
1773     i = 0
1774     while True:
1775       if i != -1:
1776         i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1777       if i != -1:
1778         revert_Argument_to_TeX_brace(document, i, 1, 3, False)
1779         i = i + 1
1780       if i == -1:
1781         return
1782
1783
1784 def convert_SIGGRAPH(document):
1785   " Converts ERT of Flex CRcat to InsetArgument "
1786   if document.textclass == "acmsiggraph":
1787     i = 0
1788     while True:
1789       if i != -1:
1790         i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1791       if i != -1:
1792         convert_TeX_brace_to_Argument(document, i, 1, 3, True, False)
1793         i = i + 1
1794       if i == -1:
1795         return
1796
1797
1798 def revert_EuropeCV(document):
1799   " Reverts InsetArguments of europeCV to TeX-code "
1800   if document.textclass == "europecv":
1801     i = 0
1802     j = 0
1803     k = 0
1804     m = 0
1805     while True:
1806       if i != -1:
1807         i = find_token(document.body, "\\begin_layout Item", i)
1808       if i != -1:
1809         revert_Argument_to_TeX_brace(document, i, 2, 2, False)
1810         i = i + 1
1811       if j != -1:
1812         j = find_token(document.body, "\\begin_layout BulletedItem", j)
1813       if j != -1:
1814         revert_Argument_to_TeX_brace(document, j, 2, 2, False)
1815         j = j + 1
1816       if k != -1:
1817         k = find_token(document.body, "\\begin_layout Language", k)
1818       if k != -1:
1819         revert_Argument_to_TeX_brace(document, k, 2, 6, False)
1820         k = k + 1
1821       if m != -1:
1822         m = find_token(document.body, "\\begin_layout LastLanguage", m)
1823       if m != -1:
1824         revert_Argument_to_TeX_brace(document, m, 2, 6, False)
1825         m = m + 1
1826       if i == -1 and j == -1 and k == -1 and m == -1:
1827         return
1828
1829
1830 def convert_EuropeCV(document):
1831   " Converts ERT of europeCV to InsetArgument "
1832   if document.textclass == "europecv":
1833     i = 0
1834     j = 0
1835     k = 0
1836     m = 0
1837     while True:
1838       if i != -1:
1839         i = find_token(document.body, "\\begin_layout Item", i)
1840       if i != -1:
1841         convert_TeX_brace_to_Argument(document, i, 2, 2, False, False)
1842         i = i + 1
1843       if j != -1:
1844         j = find_token(document.body, "\\begin_layout BulletedItem", j)
1845       if j != -1:
1846         convert_TeX_brace_to_Argument(document, j, 2, 2, False, False)
1847         j = j + 1
1848       if k != -1:
1849         k = find_token(document.body, "\\begin_layout Language", k)
1850       if k != -1:
1851         convert_TeX_brace_to_Argument(document, k, 2, 6, False, False)
1852         k = k + 1
1853       if m != -1:
1854         m = find_token(document.body, "\\begin_layout LastLanguage", m)
1855       if m != -1:
1856         convert_TeX_brace_to_Argument(document, m, 2, 6, False, False)
1857         m = m + 1
1858       if i == -1 and j == -1 and k == -1 and m == -1:
1859         return
1860
1861
1862 def revert_ModernCV(document):
1863   " Reverts InsetArguments of modernCV to TeX-code "
1864   if document.textclass == "moderncv":
1865     i = 0
1866     j = 0
1867     k = 0
1868     m = 0
1869     o = 0
1870     while True:
1871       if i != -1:
1872         i = find_token(document.body, "\\begin_layout DoubleItem", i)
1873       if i != -1:
1874         revert_Argument_to_TeX_brace(document, i, 1, 3, False)
1875         i = i + 1
1876       if j != -1:
1877         j = find_token(document.body, "\\begin_layout Entry", j)
1878       if j != -1:
1879         revert_Argument_to_TeX_brace(document, j, 1, 5, False)
1880         j = j + 1
1881       if k != -1:
1882         k = find_token(document.body, "\\begin_layout Item", k)
1883       if k != -1:
1884         revert_Argument_to_TeX_brace(document, k, 1, 1, False)
1885         k = k + 1
1886       if m != -1:
1887         m = find_token(document.body, "\\begin_layout ItemWithComment", m)
1888       if m != -1:
1889         revert_Argument_to_TeX_brace(document, m, 1, 2, False)
1890         document.body[m] = document.body[m].replace("\\begin_layout ItemWithComment", "\\begin_layout Language")
1891         m = m + 1
1892       if o != -1:
1893         o = find_token(document.body, "\\begin_layout DoubleItem", o)
1894       if o != -1:
1895         revert_Argument_to_TeX_brace(document, o, 1, 3, False)
1896         document.body[o] = document.body[o].replace("\\begin_layout DoubleItem", "\\begin_layout Computer")
1897         o = o + 1
1898       if i == -1 and j == -1 and k == -1 and m == -1 and o == -1:
1899         return
1900
1901
1902 def convert_ModernCV(document):
1903   " Converts ERT of modernCV to InsetArgument "
1904   if document.textclass == "moderncv":
1905     i = 0
1906     j = 0
1907     k = 0
1908     m = 0
1909     o = 0
1910     while True:
1911       if i != -1:
1912         i = find_token(document.body, "\\begin_layout DoubleItem", i)
1913       if i != -1:
1914         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1915         document.body[o] = document.body[o].replace("\\begin_layout DoubleItem", "\\begin_layout DoubleListItem")
1916         i = i + 1
1917       if j != -1:
1918         j = find_token(document.body, "\\begin_layout Entry", j)
1919       if j != -1:
1920         convert_TeX_brace_to_Argument(document, j, 1, 5, False, False)
1921         j = j + 1
1922       if k != -1:
1923         k = find_token(document.body, "\\begin_layout Item", k)
1924       if k != -1:
1925         convert_TeX_brace_to_Argument(document, k, 1, 1, False, False)
1926         k = k + 1
1927       if m != -1:
1928         m = find_token(document.body, "\\begin_layout Language", m)
1929       if m != -1:
1930         convert_TeX_brace_to_Argument(document, m, 1, 2, False, False)
1931         m = m + 1
1932       if i == -1 and j == -1 and k == -1 and m == -1:
1933         return
1934
1935
1936 def revert_Initials(document):
1937   " Reverts InsetArgument of Initial to TeX-code "
1938   i = 0
1939   while True:
1940     if i != -1:
1941       i = find_token(document.body, "\\begin_layout Initial", i)
1942     if i != -1:
1943       # first arg (optional) and second arg (first mandatory) are supported in LyX 2.0.x
1944       revert_Argument_to_TeX_brace(document, i, 3, 3, False)
1945       i = i + 1
1946     if i == -1:
1947       return
1948
1949
1950 def convert_Initials(document):
1951   " Converts ERT of Initial to InsetArgument "
1952   i = 0
1953   while True:
1954     if i != -1:
1955       i = find_token(document.body, "\\begin_layout Initial", i)
1956     if i != -1:
1957       convert_TeX_brace_to_Argument(document, i, 3, 3, False, False)
1958       i = i + 1
1959     if i == -1:
1960       return
1961
1962
1963 def revert_literate(document):
1964     " Revert Literate document to old format "
1965     if del_token(document.header, "noweb", 0):
1966       document.textclass = "literate-" + document.textclass
1967       i = 0
1968       while True:
1969         i = find_token(document.body, "\\begin_layout Chunk", i)
1970         if i == -1:
1971           break
1972         document.body[i] = "\\begin_layout Scrap"
1973         i = i + 1
1974
1975
1976 def convert_literate(document):
1977     " Convert Literate document to new format"
1978     i = find_token(document.header, "\\textclass", 0)    
1979     if (i != -1) and "literate-" in document.header[i]:
1980       document.textclass = document.header[i].replace("\\textclass literate-", "")
1981       j = find_token(document.header, "\\begin_modules", 0)
1982       if (j != -1):
1983         document.header.insert(j + 1, "noweb")
1984       else:
1985         document.header.insert(i + 1, "\\end_modules")
1986         document.header.insert(i + 1, "noweb")
1987         document.header.insert(i + 1, "\\begin_modules")
1988       i = 0
1989       while True:
1990         i = find_token(document.body, "\\begin_layout Scrap", i)
1991         if i == -1:
1992           break
1993         document.body[i] = "\\begin_layout Chunk"
1994         i = i + 1
1995
1996
1997 def revert_itemargs(document):
1998     " Reverts \\item arguments to TeX-code "
1999     i = 0
2000     while True:
2001         i = find_token(document.body, "\\begin_inset Argument item:", i)
2002         if i == -1:
2003             return
2004         j = find_end_of_inset(document.body, i)
2005         # Find containing paragraph layout
2006         parent = get_containing_layout(document.body, i)
2007         if parent == False:
2008             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2009             i = i + 1
2010             continue
2011         parbeg = parent[3]
2012         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2013         endPlain = find_end_of_layout(document.body, beginPlain)
2014         content = document.body[beginPlain + 1 : endPlain]
2015         del document.body[i:j+1]
2016         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2017         document.body[parbeg : parbeg] = subst
2018         i = i + 1
2019
2020
2021 def revert_garamondx_newtxmath(document):
2022     " Revert native garamond newtxmath definition to LaTeX " 
2023
2024     i = find_token(document.header, "\\font_math", 0)
2025     if i == -1:
2026        return
2027     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
2028         val = get_value(document.header, "\\font_math", i)
2029         if val == "garamondx-ntxm":
2030             add_to_preamble(document, "\\usepackage[garamondx]{newtxmath}")
2031             document.header[i] = "\\font_math auto"
2032
2033
2034 def revert_garamondx(document):
2035     " Revert native garamond font definition to LaTeX " 
2036
2037     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
2038         i = find_token(document.header, "\\font_roman garamondx", 0)
2039         if i != -1:
2040             osf = False
2041             j = find_token(document.header, "\\font_osf true", 0)
2042             if j != -1:
2043                 osf = True
2044             preamble = "\\usepackage"
2045             if osf:
2046                 preamble += "[osfI]"
2047             preamble += "{garamondx}"
2048             add_to_preamble(document, [preamble])
2049             document.header[i] = "\\font_roman default"
2050
2051
2052 def convert_beamerargs(document):
2053     " Converts beamer arguments to new layout "
2054     
2055     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2056     if document.textclass not in beamer_classes:
2057         return
2058
2059     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2060     list_layouts = ["Itemize", "Enumerate", "Description"]
2061     rx = re.compile(r'^\\begin_inset Argument (\d+)$')
2062
2063     i = 0
2064     while True:
2065         i = find_token(document.body, "\\begin_inset Argument", i)
2066         if i == -1:
2067             return
2068         # Find containing paragraph layout
2069         parent = get_containing_layout(document.body, i)
2070         if parent == False:
2071             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2072             i = i + 1
2073             continue
2074         parbeg = parent[1]
2075         parend = parent[2]
2076         layoutname = parent[0]
2077         for p in range(parbeg, parend):
2078             if layoutname in shifted_layouts:
2079                 m = rx.match(document.body[p])
2080                 if m:
2081                     argnr = int(m.group(1))
2082                     argnr += 1
2083                     document.body[p] = "\\begin_inset Argument %d" % argnr
2084             if layoutname == "AgainFrame":
2085                 m = rx.match(document.body[p])
2086                 if m:
2087                     document.body[p] = "\\begin_inset Argument 3"
2088                     if document.body[p + 4] == "\\begin_inset ERT":
2089                         if document.body[p + 9].startswith("<"):
2090                             # This is an overlay specification
2091                             # strip off the <
2092                             document.body[p + 9] = document.body[p + 9][1:]
2093                             if document.body[p + 9].endswith(">"):
2094                                 # strip off the >
2095                                 document.body[p + 9] = document.body[p + 9][:-1]
2096                                 # Shift this one
2097                                 document.body[p] = "\\begin_inset Argument 2"
2098             if layoutname in list_layouts:
2099                 m = rx.match(document.body[p])
2100                 if m:
2101                     if m.group(1) == "1":
2102                         if document.body[p + 4] == "\\begin_inset ERT":
2103                             if document.body[p + 9].startswith("<"):
2104                                 # This is an overlay specification
2105                                 # strip off the <
2106                                 document.body[p + 9] = document.body[p + 9][1:]
2107                                 if document.body[p + 9].endswith(">"):
2108                                     # strip off the >
2109                                     document.body[p + 9] = document.body[p + 9][:-1]
2110                         elif layoutname != "Itemize":
2111                             # Shift this one
2112                             document.body[p] = "\\begin_inset Argument 2"
2113         i = i + 1
2114
2115
2116 def convert_againframe_args(document):
2117     " Converts beamer AgainFrame to new layout "
2118
2119     # FIXME: This currently only works if the arguments are in one single ERT
2120     
2121     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2122     if document.textclass not in beamer_classes:
2123         return
2124    
2125     i = 0
2126     while True:
2127         i = find_token(document.body, "\\begin_layout AgainFrame", i)
2128         if i == -1:
2129             break
2130         parent = get_containing_layout(document.body, i)
2131         if parent[1] != i:
2132             document.warning("Wrong parent layout!")
2133         j = parent[2]
2134         parbeg = parent[3]
2135         if i != -1:
2136             if document.body[parbeg] == "\\begin_inset ERT":
2137                 ertcont = parbeg + 5
2138                 if document.body[ertcont].startswith("[<"):
2139                     # This is a default overlay specification
2140                     # strip off the [<
2141                     document.body[ertcont] = document.body[ertcont][2:]
2142                     if document.body[ertcont].endswith(">]"):
2143                         # strip off the >]
2144                         document.body[ertcont] = document.body[ertcont][:-2]
2145                     elif document.body[ertcont].endswith("]"):
2146                         # divide the args
2147                         tok = document.body[ertcont].find('>][')
2148                         if tok != -1:
2149                             subst = [document.body[ertcont][:tok],
2150                                      '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2151                                      'status collapsed', '', '\\begin_layout Plain Layout',
2152                                      document.body[ertcont][tok + 3:-1]]
2153                             document.body[ertcont : ertcont + 1] = subst
2154                      # Convert to ArgInset
2155                     document.body[parbeg] = "\\begin_inset Argument 2"
2156                     i = j
2157                     continue
2158                 elif document.body[ertcont].startswith("<"):
2159                     # This is an overlay specification
2160                     # strip off the <
2161                     document.body[ertcont] = document.body[ertcont][1:]
2162                     if document.body[ertcont].endswith(">"):
2163                         # strip off the >
2164                         document.body[ertcont] = document.body[ertcont][:-1]
2165                         # Convert to ArgInset
2166                         document.body[parbeg] = "\\begin_inset Argument 1"
2167                     elif document.body[ertcont].endswith(">]"):
2168                         # divide the args
2169                         tok = document.body[ertcont].find('>[<')
2170                         if tok != -1:
2171                            document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2172                                                            '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2173                                                            'status collapsed', '', '\\begin_layout Plain Layout',
2174                                                            document.body[ertcont][tok + 3:-2]]
2175                         # Convert to ArgInset
2176                         document.body[parbeg] = "\\begin_inset Argument 1"
2177                     elif document.body[ertcont].endswith("]"):
2178                         # divide the args
2179                         tok = document.body[ertcont].find('>[<')
2180                         if tok != -1:
2181                            # divide the args
2182                            tokk = document.body[ertcont].find('>][')
2183                            if tokk != -1:
2184                                document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2185                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2186                                                                'status collapsed', '', '\\begin_layout Plain Layout',
2187                                                                document.body[ertcont][tok + 3:tokk],
2188                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2189                                                                'status collapsed', '', '\\begin_layout Plain Layout',
2190                                                                document.body[ertcont][tokk + 3:-1]]
2191                         else:
2192                             tokk = document.body[ertcont].find('>[')
2193                             if tokk != -1:
2194                                 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tokk],
2195                                                                 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2196                                                                 'status collapsed', '', '\\begin_layout Plain Layout',
2197                                                                 document.body[ertcont][tokk + 2:-1]]
2198                         # Convert to ArgInset
2199                         document.body[parbeg] = "\\begin_inset Argument 1"
2200                     i = j
2201                     continue
2202                 elif document.body[ertcont].startswith("["):
2203                     # This is an ERT option
2204                     # strip off the [
2205                     document.body[ertcont] = document.body[ertcont][1:]
2206                     if document.body[ertcont].endswith("]"):
2207                         # strip off the ]
2208                         document.body[ertcont] = document.body[ertcont][:-1]
2209                         # Convert to ArgInset
2210                         document.body[parbeg] = "\\begin_inset Argument 3"
2211                     i = j
2212                     continue
2213         i = j
2214
2215
2216 def convert_corollary_args(document):
2217     " Converts beamer corrolary-style ERT arguments native InsetArgs "
2218     
2219     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2220     if document.textclass not in beamer_classes:
2221         return
2222    
2223     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2224     for lay in corollary_layouts:
2225         i = 0
2226         while True:
2227             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2228             if i == -1:
2229                 break
2230             parent = get_containing_layout(document.body, i)
2231             if parent[1] != i:
2232                 document.warning("Wrong parent layout!")
2233             j = parent[2]
2234             parbeg = parent[3]
2235             if i != -1:
2236                 if document.body[parbeg] == "\\begin_inset ERT":
2237                     ertcont = parbeg + 5
2238                     if document.body[ertcont].startswith("<"):
2239                         # This is an overlay specification
2240                         # strip off the <
2241                         document.body[ertcont] = document.body[ertcont][1:]
2242                         if document.body[ertcont].endswith(">"):
2243                             # strip off the >
2244                             document.body[ertcont] = document.body[ertcont][:-1]
2245                         elif document.body[ertcont].endswith("]"):
2246                             # divide the args
2247                             tok = document.body[ertcont].find('>[')
2248                             if tok != -1:
2249                                 subst = [document.body[ertcont][:tok],
2250                                          '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2251                                          'status collapsed', '', '\\begin_layout Plain Layout',
2252                                          document.body[ertcont][tok + 2:-1]]
2253                                 document.body[ertcont : ertcont + 1] = subst
2254                         # Convert to ArgInset
2255                         document.body[parbeg] = "\\begin_inset Argument 1"
2256                         i = j
2257                         continue
2258                     elif document.body[ertcont].startswith("["):
2259                         # This is an ERT option
2260                         # strip off the [
2261                         document.body[ertcont] = document.body[ertcont][1:]
2262                         if document.body[ertcont].endswith("]"):
2263                             # strip off the ]
2264                             document.body[ertcont] = document.body[ertcont][:-1]
2265                         # Convert to ArgInset
2266                         document.body[parbeg] = "\\begin_inset Argument 2"
2267                     i = j
2268                     continue
2269             i = j
2270
2271
2272
2273 def convert_quote_args(document):
2274     " Converts beamer quote style ERT args to native InsetArgs "
2275     
2276     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2277     if document.textclass not in beamer_classes:
2278         return
2279    
2280     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2281     for lay in quote_layouts:
2282         i = 0
2283         while True:
2284             i = find_token(document.body, "\\begin_layout " + lay, i)
2285             if i == -1:
2286                 break
2287             parent = get_containing_layout(document.body, i)
2288             if parent[1] != i:
2289                 document.warning("Wrong parent layout!")
2290             j = parent[2]
2291             parbeg = parent[3]
2292             if i != -1:
2293                 if document.body[parbeg] == "\\begin_inset ERT":
2294                     if document.body[i + 6].startswith("<"):
2295                         # This is an overlay specification
2296                         # strip off the <
2297                         document.body[i + 6] = document.body[i + 6][1:]
2298                         if document.body[i + 6].endswith(">"):
2299                             # strip off the >
2300                             document.body[i + 6] = document.body[i + 6][:-1]
2301                             # Convert to ArgInset
2302                             document.body[i + 1] = "\\begin_inset Argument 1"
2303             i = j
2304
2305
2306 def revert_beamerargs(document):
2307     " Reverts beamer arguments to old layout "
2308     
2309     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2310     if document.textclass not in beamer_classes:
2311         return
2312
2313     i = 0
2314     list_layouts = ["Itemize", "Enumerate", "Description"]
2315     headings = ["Part", "Section", "Section*", "Subsection", "Subsection*",
2316                 "Subsubsection", "Subsubsection*", "FrameSubtitle", "NoteItem"]
2317     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2318     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2319     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2320
2321     while True:
2322         i = find_token(document.body, "\\begin_inset Argument", i)
2323         if i == -1:
2324             return
2325         # Find containing paragraph layout
2326         parent = get_containing_layout(document.body, i)
2327         if parent == False:
2328             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2329             i = i + 1
2330             continue
2331         parbeg = parent[1]
2332         parend = parent[2]
2333         realparbeg = parent[3]
2334         layoutname = parent[0]
2335         realparend = parend
2336         for p in range(parbeg, parend):
2337             if p >= realparend:
2338                 i = realparend
2339                 break
2340             if layoutname in headings:
2341                 m = rx.match(document.body[p])
2342                 if m:
2343                     argnr = m.group(1)
2344                     if argnr == "1":
2345                         # Find containing paragraph layout
2346                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2347                         endPlain = find_end_of_layout(document.body, beginPlain)
2348                         endInset = find_end_of_inset(document.body, p)
2349                         argcontent = document.body[beginPlain + 1 : endPlain]
2350                         # Adjust range end
2351                         realparend = realparend - len(document.body[p : endInset + 1])
2352                         # Remove arg inset
2353                         del document.body[p : endInset + 1]
2354                         if layoutname == "FrameSubtitle":
2355                             pre = put_cmd_in_ert("\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2356                         elif layoutname == "NoteItem":
2357                             pre = put_cmd_in_ert("\\note<") + argcontent + put_cmd_in_ert(">[item]")
2358                         elif layoutname.endswith('*'):
2359                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower()[:-1] + "<") + argcontent + put_cmd_in_ert(">*")
2360                         else:
2361                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2362                         secarg = find_token(document.body, "\\begin_inset Argument 2", parbeg, parend)
2363                         if secarg != -1:
2364                             # Find containing paragraph layout
2365                             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", secarg)
2366                             endPlain = find_end_of_layout(document.body, beginPlain)
2367                             endInset = find_end_of_inset(document.body, secarg)
2368                             argcontent = document.body[beginPlain + 1 : endPlain]
2369                             # Adjust range end
2370                             realparend = realparend - len(document.body[secarg : endInset + 1])
2371                             del document.body[secarg : endInset + 1]
2372                             pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2373                         pre += put_cmd_in_ert("{")
2374                         document.body[parbeg] = "\\begin_layout Standard"
2375                         document.body[realparbeg : realparbeg] = pre
2376                         pe = find_end_of_layout(document.body, parbeg)
2377                         post = put_cmd_in_ert("}")
2378                         document.body[pe : pe] = post
2379                         realparend += len(pre) + len(post)
2380             if layoutname == "AgainFrame":
2381                 m = rx.match(document.body[p])
2382                 if m:
2383                     argnr = m.group(1)
2384                     if argnr == "3":
2385                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2386                         endPlain = find_end_of_layout(document.body, beginPlain)
2387                         endInset = find_end_of_inset(document.body, p)
2388                         content = document.body[beginPlain + 1 : endPlain]
2389                         # Adjust range end
2390                         realparend = realparend - len(document.body[p : endInset + 1])
2391                         # Remove arg inset
2392                         del document.body[p : endInset + 1]
2393                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2394                         document.body[realparbeg : realparbeg] = subst
2395             if layoutname == "Overprint":
2396                 m = rx.match(document.body[p])
2397                 if m:
2398                     argnr = m.group(1)
2399                     if argnr == "1":
2400                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2401                         endPlain = find_end_of_layout(document.body, beginPlain)
2402                         endInset = find_end_of_inset(document.body, p)
2403                         content = document.body[beginPlain + 1 : endPlain]
2404                         # Adjust range end
2405                         realparend = realparend - len(document.body[p : endInset + 1])
2406                         # Remove arg inset
2407                         del document.body[p : endInset + 1]
2408                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2409                         document.body[realparbeg : realparbeg] = subst
2410             if layoutname == "OverlayArea":
2411                 m = rx.match(document.body[p])
2412                 if m:
2413                     argnr = m.group(1)
2414                     if argnr == "2":
2415                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2416                         endPlain = find_end_of_layout(document.body, beginPlain)
2417                         endInset = find_end_of_inset(document.body, p)
2418                         content = document.body[beginPlain + 1 : endPlain]
2419                         # Adjust range end
2420                         realparend = realparend - len(document.body[p : endInset + 1])
2421                         # Remove arg inset
2422                         del document.body[p : endInset + 1]
2423                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2424                         document.body[realparbeg : realparbeg] = subst
2425             if layoutname in list_layouts:
2426                 m = rx.match(document.body[p])
2427                 if m:
2428                     argnr = m.group(1)
2429                     if argnr == "1":
2430                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2431                         endPlain = find_end_of_layout(document.body, beginPlain)
2432                         endInset = find_end_of_inset(document.body, p)
2433                         content = document.body[beginPlain + 1 : endPlain]
2434                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2435                         realparend = realparend + len(subst) - len(content)
2436                         document.body[beginPlain + 1 : endPlain] = subst
2437                     elif argnr == "item:1":
2438                         j = find_end_of_inset(document.body, i)
2439                         # Find containing paragraph layout
2440                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2441                         endPlain = find_end_of_layout(document.body, beginPlain)
2442                         content = document.body[beginPlain + 1 : endPlain]
2443                         del document.body[i:j+1]
2444                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2445                         document.body[realparbeg : realparbeg] = subst
2446                     elif argnr == "item:2":
2447                         j = find_end_of_inset(document.body, i)
2448                         # Find containing paragraph layout
2449                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2450                         endPlain = find_end_of_layout(document.body, beginPlain)
2451                         content = document.body[beginPlain + 1 : endPlain]
2452                         del document.body[i:j+1]
2453                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2454                         document.body[realparbeg : realparbeg] = subst
2455             if layoutname in quote_layouts:
2456                 m = rx.match(document.body[p])
2457                 if m:
2458                     argnr = m.group(1)
2459                     if argnr == "1":
2460                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2461                         endPlain = find_end_of_layout(document.body, beginPlain)
2462                         endInset = find_end_of_inset(document.body, p)
2463                         content = document.body[beginPlain + 1 : endPlain]
2464                         # Adjust range end
2465                         realparend = realparend - len(document.body[p : endInset + 1])
2466                         # Remove arg inset
2467                         del document.body[p : endInset + 1]
2468                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2469                         document.body[realparbeg : realparbeg] = subst
2470             if layoutname in corollary_layouts:
2471                 m = rx.match(document.body[p])
2472                 if m:
2473                     argnr = m.group(1)
2474                     if argnr == "2":
2475                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2476                         endPlain = find_end_of_layout(document.body, beginPlain)
2477                         endInset = find_end_of_inset(document.body, p)
2478                         content = document.body[beginPlain + 1 : endPlain]
2479                         # Adjust range end
2480                         realparend = realparend - len(document.body[p : endInset + 1])
2481                         # Remove arg inset
2482                         del document.body[p : endInset + 1]
2483                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2484                         document.body[realparbeg : realparbeg] = subst
2485         
2486         i = realparend
2487
2488
2489 def revert_beamerargs2(document):
2490     " Reverts beamer arguments to old layout, step 2 "
2491     
2492     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2493     if document.textclass not in beamer_classes:
2494         return
2495
2496     i = 0
2497     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2498     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2499     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2500
2501     while True:
2502         i = find_token(document.body, "\\begin_inset Argument", i)
2503         if i == -1:
2504             return
2505         # Find containing paragraph layout
2506         parent = get_containing_layout(document.body, i)
2507         if parent == False:
2508             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2509             i = i + 1
2510             continue
2511         parbeg = parent[1]
2512         parend = parent[2]
2513         realparbeg = parent[3]
2514         layoutname = parent[0]
2515         realparend = parend
2516         for p in range(parbeg, parend):
2517             if p >= realparend:
2518                 i = realparend
2519                 break
2520             if layoutname in shifted_layouts:
2521                 m = rx.match(document.body[p])
2522                 if m:
2523                     argnr = m.group(1)
2524                     if argnr == "2":
2525                         document.body[p] = "\\begin_inset Argument 1"       
2526             if layoutname in corollary_layouts:
2527                 m = rx.match(document.body[p])
2528                 if m:
2529                     argnr = m.group(1)
2530                     if argnr == "1":
2531                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2532                         endPlain = find_end_of_layout(document.body, beginPlain)
2533                         endInset = find_end_of_inset(document.body, p)
2534                         content = document.body[beginPlain + 1 : endPlain]
2535                         # Adjust range end
2536                         realparend = realparend - len(document.body[p : endInset + 1])
2537                         # Remove arg inset
2538                         del document.body[p : endInset + 1]
2539                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2540                         document.body[realparbeg : realparbeg] = subst
2541             if layoutname == "OverlayArea":
2542                 m = rx.match(document.body[p])
2543                 if m:
2544                     argnr = m.group(1)
2545                     if argnr == "1":
2546                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2547                         endPlain = find_end_of_layout(document.body, beginPlain)
2548                         endInset = find_end_of_inset(document.body, p)
2549                         content = document.body[beginPlain + 1 : endPlain]
2550                         # Adjust range end
2551                         realparend = realparend - len(document.body[p : endInset + 1])
2552                         # Remove arg inset
2553                         del document.body[p : endInset + 1]
2554                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2555                         document.body[realparbeg : realparbeg] = subst
2556             if layoutname == "AgainFrame":
2557                 m = rx.match(document.body[p])
2558                 if m:
2559                     argnr = m.group(1)
2560                     if argnr == "2":
2561                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2562                         endPlain = find_end_of_layout(document.body, beginPlain)
2563                         endInset = find_end_of_inset(document.body, p)
2564                         content = document.body[beginPlain + 1 : endPlain]
2565                         # Adjust range end
2566                         realparend = realparend - len(document.body[p : endInset + 1])
2567                         # Remove arg inset
2568                         del document.body[p : endInset + 1]
2569                         subst = put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
2570                         document.body[realparbeg : realparbeg] = subst
2571         i = realparend
2572
2573
2574 def revert_beamerargs3(document):
2575     " Reverts beamer arguments to old layout, step 3 "
2576     
2577     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2578     if document.textclass not in beamer_classes:
2579         return
2580
2581     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2582     i = 0
2583     while True:
2584         i = find_token(document.body, "\\begin_inset Argument", i)
2585         if i == -1:
2586             return
2587         # Find containing paragraph layout
2588         parent = get_containing_layout(document.body, i)
2589         if parent == False:
2590             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2591             i = i + 1
2592             continue
2593         parbeg = parent[1]
2594         parend = parent[2]
2595         realparbeg = parent[3]
2596         layoutname = parent[0]
2597         realparend = parend
2598         for p in range(parbeg, parend):
2599             if p >= realparend:
2600                 i = realparend
2601                 break
2602             if layoutname == "AgainFrame":
2603                 m = rx.match(document.body[p])
2604                 if m:
2605                     argnr = m.group(1)
2606                     if argnr == "1":
2607                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2608                         endPlain = find_end_of_layout(document.body, beginPlain)
2609                         endInset = find_end_of_inset(document.body, p)
2610                         content = document.body[beginPlain + 1 : endPlain]
2611                         # Adjust range end
2612                         realparend = realparend - len(document.body[p : endInset + 1])
2613                         # Remove arg inset
2614                         del document.body[p : endInset + 1]
2615                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2616                         document.body[realparbeg : realparbeg] = subst
2617         i = realparend
2618
2619
2620 def revert_beamerflex(document):
2621     " Reverts beamer Flex insets "
2622     
2623     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2624     if document.textclass not in beamer_classes:
2625         return
2626
2627     new_flexes = {"Bold" : "\\textbf", "Emphasize" : "\\emph", "Only" : "\\only",
2628                   "Uncover" : "\\uncover", "Visible" : "\\visible",
2629                   "Invisible" : "\\invisible", "Alternative" : "\\alt",
2630                   "Beamer_Note" : "\\note"}
2631     old_flexes = {"Alert" : "\\alert", "Structure" : "\\structure"}
2632     rx = re.compile(r'^\\begin_inset Flex (.+)$')
2633
2634     i = 0
2635     while True:
2636         i = find_token(document.body, "\\begin_inset Flex", i)
2637         if i == -1:
2638             return
2639         m = rx.match(document.body[i])
2640         if m:
2641             flextype = m.group(1)
2642             z = find_end_of_inset(document.body, i)
2643             if z == -1:
2644                 document.warning("Can't find end of Flex " + flextype + " inset.")
2645                 i += 1
2646                 continue
2647             if flextype in new_flexes:
2648                 pre = put_cmd_in_ert(new_flexes[flextype])
2649                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2650                 if arg != -1:
2651                     argend = find_end_of_inset(document.body, arg)
2652                     if argend == -1:
2653                         document.warning("Can't find end of Argument!")
2654                         i += 1
2655                         continue
2656                     # Find containing paragraph layout
2657                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2658                     endPlain = find_end_of_layout(document.body, beginPlain)
2659                     argcontent = document.body[beginPlain + 1 : endPlain]
2660                     # Adjust range end
2661                     z = z - len(document.body[arg : argend + 1])
2662                     # Remove arg inset
2663                     del document.body[arg : argend + 1]
2664                     pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2665                 arg = find_token(document.body, "\\begin_inset Argument 2", i, z)
2666                 if arg != -1:
2667                     argend = find_end_of_inset(document.body, arg)
2668                     if argend == -1:
2669                         document.warning("Can't find end of Argument!")
2670                         i += 1
2671                         continue
2672                     # Find containing paragraph layout
2673                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2674                     endPlain = find_end_of_layout(document.body, beginPlain)
2675                     argcontent = document.body[beginPlain + 1 : endPlain]
2676                     # Adjust range end
2677                     z = z - len(document.body[arg : argend + 1])
2678                     # Remove arg inset
2679                     del document.body[arg : argend + 1]
2680                     if flextype == "Alternative":
2681                         pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
2682                     else:
2683                         pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2684                 pre += put_cmd_in_ert("{")
2685                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2686                 endPlain = find_end_of_layout(document.body, beginPlain)
2687                 # Adjust range end
2688                 z = z - len(document.body[i : beginPlain + 1])
2689                 z += len(pre)
2690                 document.body[i : beginPlain + 1] = pre
2691                 post = put_cmd_in_ert("}")
2692                 document.body[z - 2 : z + 1] = post
2693             elif flextype in old_flexes:
2694                 pre = put_cmd_in_ert(old_flexes[flextype])
2695                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2696                 if arg == -1:
2697                     i += 1
2698                     continue
2699                 argend = find_end_of_inset(document.body, arg)
2700                 if argend == -1:
2701                     document.warning("Can't find end of Argument!")
2702                     i += 1
2703                     continue
2704                 # Find containing paragraph layout
2705                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2706                 endPlain = find_end_of_layout(document.body, beginPlain)
2707                 argcontent = document.body[beginPlain + 1 : endPlain]
2708                 # Adjust range end
2709                 z = z - len(document.body[arg : argend + 1])
2710                 # Remove arg inset
2711                 del document.body[arg : argend + 1]
2712                 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2713                 pre += put_cmd_in_ert("{")
2714                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2715                 endPlain = find_end_of_layout(document.body, beginPlain)
2716                 # Adjust range end
2717                 z = z - len(document.body[i : beginPlain + 1])
2718                 z += len(pre)
2719                 document.body[i : beginPlain + 1] = pre
2720                 post = put_cmd_in_ert("}")
2721                 document.body[z - 2 : z + 1] = post
2722         
2723         i += 1
2724
2725
2726 def revert_beamerblocks(document):
2727     " Reverts beamer block arguments to ERT "
2728     
2729     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2730     if document.textclass not in beamer_classes:
2731         return
2732
2733     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2734
2735     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2736     i = 0
2737     while True:
2738         i = find_token(document.body, "\\begin_inset Argument", i)
2739         if i == -1:
2740             return
2741         # Find containing paragraph layout
2742         parent = get_containing_layout(document.body, i)
2743         if parent == False:
2744             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2745             i = i + 1
2746             continue
2747         parbeg = parent[1]
2748         parend = parent[2]
2749         realparbeg = parent[3]
2750         layoutname = parent[0]
2751         realparend = parend
2752         for p in range(parbeg, parend):
2753             if p >= realparend:
2754                 i = realparend
2755                 break
2756             if layoutname in blocks:
2757                 m = rx.match(document.body[p])
2758                 if m:
2759                     argnr = m.group(1)
2760                     if argnr == "1":
2761                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2762                         endPlain = find_end_of_layout(document.body, beginPlain)
2763                         endInset = find_end_of_inset(document.body, p)
2764                         content = document.body[beginPlain + 1 : endPlain]
2765                         # Adjust range end
2766                         realparend = realparend - len(document.body[p : endInset + 1])
2767                         # Remove arg inset
2768                         del document.body[p : endInset + 1]
2769                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2770                         document.body[realparbeg : realparbeg] = subst
2771                     elif argnr == "2":
2772                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2773                         endPlain = find_end_of_layout(document.body, beginPlain)
2774                         endInset = find_end_of_inset(document.body, p)
2775                         content = document.body[beginPlain + 1 : endPlain]
2776                         # Adjust range end
2777                         realparend = realparend - len(document.body[p : endInset + 1])
2778                         # Remove arg inset
2779                         del document.body[p : endInset + 1]
2780                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2781                         document.body[realparbeg : realparbeg] = subst
2782         i = realparend
2783
2784
2785
2786 def convert_beamerblocks(document):
2787     " Converts beamer block ERT args to native InsetArgs "
2788     
2789     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2790     if document.textclass not in beamer_classes:
2791         return
2792    
2793     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2794     for lay in blocks:
2795         i = 0
2796         while True:
2797             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2798             if i == -1:
2799                 break
2800             parent = get_containing_layout(document.body, i)
2801             if parent == False or parent[1] != i:
2802                 document.warning("Wrong parent layout!")
2803                 i += 1
2804                 continue
2805             j = parent[2]
2806             parbeg = parent[3]
2807             if i != -1:
2808                 if document.body[parbeg] == "\\begin_inset ERT":
2809                     ertcont = parbeg + 5
2810                     while True:
2811                         if document.body[ertcont].startswith("<"):
2812                             # This is an overlay specification
2813                             # strip off the <
2814                             document.body[ertcont] = document.body[ertcont][1:]
2815                             if document.body[ertcont].endswith(">"):
2816                                 # strip off the >
2817                                 document.body[ertcont] = document.body[ertcont][:-1]
2818                                 # Convert to ArgInset
2819                                 document.body[parbeg] = "\\begin_inset Argument 1"
2820                             elif document.body[ertcont].endswith("}"):
2821                                 # divide the args
2822                                 tok = document.body[ertcont].find('>{')
2823                                 if tok != -1:
2824                                     document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2825                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2826                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
2827                                                                             document.body[ertcont][tok + 2:-1]]
2828                             # Convert to ArgInset
2829                             document.body[parbeg] = "\\begin_inset Argument 1"
2830                         elif document.body[ertcont].startswith("{"):
2831                             # This is the block title
2832                             if document.body[ertcont].endswith("}"):
2833                                 # strip off the braces
2834                                 document.body[ertcont] = document.body[ertcont][1:-1]
2835                                 # Convert to ArgInset
2836                                 document.body[parbeg] = "\\begin_inset Argument 2"
2837                             elif count_pars_in_inset(document.body, ertcont) > 1:
2838                                 # Multipar ERT. Skip this.
2839                                 break
2840                             else:
2841                                 convert_TeX_brace_to_Argument(document, i, 2, 2, False, True)
2842                         else:
2843                             break
2844                         j = find_end_of_layout(document.body, i)
2845                         if j == -1:
2846                             document.warning("end of layout not found!")
2847                         k = find_token(document.body, "\\begin_inset Argument", i, j)
2848                         if k == -1:
2849                             document.warning("InsetArgument not found!")
2850                             break
2851                         l = find_end_of_inset(document.body, k)
2852                         m = find_token(document.body, "\\begin_inset ERT", l, j)
2853                         if m == -1:
2854                             break
2855                         ertcont = m + 5
2856                         parbeg = m
2857             i = j
2858
2859
2860 def convert_overprint(document):
2861     " Convert old beamer overprint layouts to ERT "
2862     
2863     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2864     if document.textclass not in beamer_classes:
2865         return
2866
2867     i = 0
2868     while True:
2869         i = find_token(document.body, "\\begin_layout Overprint", i)
2870         if i == -1:
2871             return
2872         # Find end of sequence
2873         j = find_end_of_sequence(document.body, i)
2874         if j == -1:
2875             document.warning("Malformed lyx document. Cannot find end of Overprint sequence!")
2876             i = i + 1
2877             continue
2878         endseq = j
2879         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
2880         esubst = list()
2881         if document.body[j] == "\\end_deeper":
2882             esubst = ["", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
2883         else:
2884             esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
2885         endseq = endseq + len(esubst) - len(document.body[j : j])
2886         document.body[j : j] = esubst
2887         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
2888         if argbeg != -1:
2889             argend = find_end_of_layout(document.body, argbeg)
2890             if argend == -1:
2891                 document.warning("Malformed lyx document. Cannot find end of Overprint argument!")
2892                 i = i + 1
2893                 continue
2894             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
2895             endPlain = find_end_of_layout(document.body, beginPlain)
2896             content = document.body[beginPlain + 1 : endPlain]
2897             # Adjust range end
2898             endseq = endseq - len(document.body[argbeg : argend + 1])
2899             # Remove arg inset
2900             del document.body[argbeg : argend + 1]
2901             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2902             
2903         endseq = endseq - len(document.body[i : i])
2904         document.body[i : i] = subst + ["\\end_layout"]
2905         endseq += len(subst)
2906         
2907         for p in range(i, endseq):
2908             if document.body[p] == "\\begin_layout Overprint":
2909                 document.body[p] = "\\begin_layout Standard"
2910
2911         i = endseq
2912
2913
2914 def revert_overprint(document):
2915     " Revert old beamer overprint layouts to ERT "
2916     
2917     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2918     if document.textclass not in beamer_classes:
2919         return
2920
2921     i = 0
2922     while True:
2923         i = find_token(document.body, "\\begin_layout Overprint", i)
2924         if i == -1:
2925             return
2926         # Find end of sequence
2927         j = find_end_of_sequence(document.body, i)
2928         if j == -1:
2929             document.warning("Malformed lyx document. Cannot find end of Overprint sequence!")
2930             i = i + 1
2931             continue
2932         endseq = j
2933         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
2934         esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}")
2935         endseq = endseq + len(esubst) - len(document.body[j : j])
2936         if document.body[j] == "\\end_deeper":
2937             document.body[j : j] = ["\\end_deeper", ""] + esubst
2938         else:
2939             document.body[j : j] = esubst
2940         r = i
2941         while r < j:
2942             if document.body[r] == "\\begin_deeper":
2943                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
2944                 if s != -1:
2945                     document.body[r] = ""
2946                     document.body[s] = ""
2947                     r = s
2948                     continue
2949             r = r + 1
2950         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
2951         if argbeg != -1:
2952             argend = find_end_of_inset(document.body, argbeg)
2953             if argend == -1:
2954                 document.warning("Malformed lyx document. Cannot find end of Overprint argument!")
2955                 i = i + 1
2956                 continue
2957             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
2958             endPlain = find_end_of_layout(document.body, beginPlain)
2959             content = document.body[beginPlain + 1 : endPlain]
2960             # Adjust range end
2961             endseq = endseq - len(document.body[argbeg : argend])
2962             # Remove arg inset
2963             del document.body[argbeg : argend + 1]
2964             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2965             
2966         endseq = endseq - len(document.body[i : i])
2967         document.body[i : i] = subst + ["\\end_layout"]
2968         endseq += len(subst)
2969      
2970         p = i
2971         while True:
2972             if p >= endseq:
2973                 break
2974             if document.body[p] == "\\begin_layout Overprint":
2975                 q = find_end_of_layout(document.body, p)
2976                 if q == -1:
2977                     document.warning("Malformed lyx document. Cannot find end of Overprint layout!")
2978                     p += 1
2979                     continue
2980                 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\onslide")
2981                 argbeg = find_token(document.body, "\\begin_inset Argument item:1", p, q)
2982                 if argbeg != -1:
2983                     argend = find_end_of_inset(document.body, argbeg)
2984                     if argend == -1:
2985                         document.warning("Malformed lyx document. Cannot find end of Overprint item argument!")
2986                         p += 1
2987                         continue
2988                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
2989                     endPlain = find_end_of_layout(document.body, beginPlain)
2990                     content = document.body[beginPlain + 1 : endPlain]
2991                     # Adjust range end
2992                     endseq = endseq - len(document.body[argbeg : argend + 1])
2993                     # Remove arg inset
2994                     del document.body[argbeg : argend + 1]
2995                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2996                 endseq = endseq - len(document.body[p : p + 1]) + len(subst)
2997                 document.body[p : p + 1] = subst
2998             p = p + 1
2999
3000         i = endseq
3001
3002
3003 def revert_frametitle(document):
3004     " Reverts beamer frametitle layout to ERT "
3005     
3006     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3007     if document.textclass not in beamer_classes:
3008         return
3009
3010     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3011     i = 0
3012     while True:
3013         i = find_token(document.body, "\\begin_layout FrameTitle", i)
3014         if i == -1:
3015             return
3016         j = find_end_of_layout(document.body, i)
3017         if j == -1:
3018             document.warning("Malformed lyx document: Can't find end of FrameTitle layout")
3019             i = i + 1
3020             continue
3021         endlay = j
3022         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
3023         endlay += len(put_cmd_in_ert("}"))
3024         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\frametitle")
3025         for p in range(i, j):
3026             if p >= endlay:
3027                 break
3028             m = rx.match(document.body[p])
3029             if m:
3030                 argnr = m.group(1)
3031                 if argnr == "1":
3032                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3033                     endPlain = find_end_of_layout(document.body, beginPlain)
3034                     endInset = find_end_of_inset(document.body, p)
3035                     content = document.body[beginPlain + 1 : endPlain]
3036                     # Adjust range end
3037                     endlay = endlay - len(document.body[p : endInset + 1])
3038                     # Remove arg inset
3039                     del document.body[p : endInset + 1]
3040                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3041                 elif argnr == "2":
3042                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3043                     endPlain = find_end_of_layout(document.body, beginPlain)
3044                     endInset = find_end_of_inset(document.body, p)
3045                     content = document.body[beginPlain + 1 : endPlain]
3046                     # Adjust range end
3047                     endlay = endlay - len(document.body[p : endInset + 1])
3048                     # Remove arg inset
3049                     del document.body[p : endInset + 1]
3050                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3051                     
3052         subst += put_cmd_in_ert("{")
3053         document.body[i : i + 1] = subst
3054         i = endlay
3055
3056
3057 def convert_epigraph(document):
3058     " Converts memoir epigraph to new syntax "
3059     
3060     if document.textclass != "memoir":
3061         return
3062
3063     i = 0
3064     while True:
3065         i = find_token(document.body, "\\begin_layout Epigraph", i)
3066         if i == -1:
3067             return
3068         j = find_end_of_layout(document.body, i)
3069         if j == -1:
3070             document.warning("Malformed lyx document: Can't find end of Epigraph layout")
3071             i = i + 1
3072             continue
3073         endlay = j
3074         subst = list()
3075         ert = find_token(document.body, "\\begin_inset ERT", i, j)
3076         if ert != -1:
3077             endInset = find_end_of_inset(document.body, ert)
3078             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", ert)
3079             endPlain = find_end_of_layout(document.body, beginPlain)
3080             ertcont = beginPlain + 2
3081             if document.body[ertcont] == "}{":
3082                 # strip off the <
3083                 # Convert to ArgInset
3084                 endlay = endlay - 2 * len(document.body[j])
3085                 begsubst = ['\\begin_inset Argument post:1', 'status collapsed', '',
3086                             '\\begin_layout Plain Layout']
3087                 endsubst = ['\\end_layout', '', '\\end_inset', '', document.body[j]]
3088                 document.body[j : j + 1] = endsubst
3089                 document.body[endInset + 1 : endInset + 1] = begsubst
3090                 # Adjust range end
3091                 endlay += len(begsubst) + len(endsubst)
3092                 endlay = endlay - len(document.body[ert : endInset + 1])
3093                 del document.body[ert : endInset + 1]
3094                     
3095         i = endlay
3096
3097
3098 def revert_epigraph(document):
3099     " Reverts memoir epigraph argument to ERT "
3100     
3101     if document.textclass != "memoir":
3102         return
3103
3104     i = 0
3105     while True:
3106         i = find_token(document.body, "\\begin_layout Epigraph", i)
3107         if i == -1:
3108             return
3109         j = find_end_of_layout(document.body, i)
3110         if j == -1:
3111             document.warning("Malformed lyx document: Can't find end of Epigraph layout")
3112             i = i + 1
3113             continue
3114         endlay = j
3115         subst = list()
3116         p = find_token(document.body, "\\begin_layout Argument post:1", i, j)
3117         if p != -1:
3118             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3119             endPlain = find_end_of_layout(document.body, beginPlain)
3120             endInset = find_end_of_inset(document.body, p)
3121             content = document.body[beginPlain + 1 : endPlain]
3122             # Adjust range end
3123             endlay = endlay - len(document.body[p : endInset + 1])
3124             # Remove arg inset
3125             del document.body[p : endInset + 1]
3126             subst += put_cmd_in_ert("}{") + content
3127         else:
3128             subst += put_cmd_in_ert("}{")
3129                     
3130         document.body[j : j] = subst + document.body[j : j]
3131         i = endlay
3132
3133
3134 def convert_captioninsets(document):
3135     " Converts caption insets to new syntax "
3136     
3137     i = 0
3138     while True:
3139       i = find_token(document.body, "\\begin_inset Caption", i)
3140       if i == -1:
3141           return
3142       document.body[i] = "\\begin_inset Caption Standard"
3143       i = i + 1
3144         
3145
3146
3147 def revert_captioninsets(document):
3148     " Reverts caption insets to old syntax "
3149     
3150     i = 0
3151     while True:
3152       i = find_token(document.body, "\\begin_inset Caption Standard", i)
3153       if i == -1:
3154           return
3155       document.body[i] = "\\begin_inset Caption"
3156       i = i + 1
3157
3158
3159 def convert_captionlayouts(document):
3160     " Convert caption layouts to caption insets. "
3161     
3162     caption_dict = {
3163         "Captionabove":  "Above",
3164         "Captionbelow":  "Below",
3165         "FigCaption"  :  "FigCaption",
3166         "Table_Caption" :  "Table",
3167         "CenteredCaption" : "Centered",
3168         "Bicaption" : "Bicaption",
3169         }
3170     
3171     i = 0
3172     while True:
3173         i = find_token(document.body, "\\begin_layout", i)
3174         if i == -1:
3175             return
3176         val = get_value(document.body, "\\begin_layout", i)
3177         if val in caption_dict.keys():
3178             j = find_end_of_layout(document.body, i)
3179             if j == -1:
3180                 document.warning("Malformed LyX document: Missing `\\end_layout'.")
3181                 return
3182
3183             document.body[j:j] = ["\\end_layout", "", "\\end_inset", "", ""]
3184             document.body[i:i+1] = ["\\begin_layout %s" % document.default_layout,
3185                                     "\\begin_inset Caption %s" % caption_dict[val], "",
3186                                     "\\begin_layout %s" % document.default_layout]
3187         i = i + 1
3188
3189
3190 def revert_captionlayouts(document):
3191     " Revert caption insets to caption layouts. "
3192     
3193     caption_dict = {
3194         "Above" : "Captionabove",
3195         "Below" : "Captionbelow",
3196         "FigCaption"  :  "FigCaption",
3197         "Table" : "Table_Caption",
3198         "Centered" : "CenteredCaption",
3199         "Bicaption" : "Bicaption",
3200         }
3201     
3202     i = 0
3203     rx = re.compile(r'^\\begin_inset Caption (\S+)$')
3204     while True:
3205         i = find_token(document.body, "\\begin_inset Caption", i)
3206         if i == -1:
3207             return
3208
3209         m = rx.match(document.body[i])
3210         val = ""
3211         if m:
3212             val = m.group(1)
3213         if val not in caption_dict.keys():
3214             i = i + 1
3215             continue
3216         
3217         # We either need to delete the previous \begin_layout line, or we
3218         # need to end the previous layout if this inset is not in the first
3219         # position of the paragraph.
3220         layout_before = find_token_backwards(document.body, "\\begin_layout", i)
3221         if layout_before == -1:
3222             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3223             return
3224         layout_line = document.body[layout_before]
3225         del_layout_before = True
3226         l = layout_before + 1
3227         while l < i:
3228             if document.body[l] != "":
3229                 del_layout_before = False
3230                 break
3231             l = l + 1
3232         if del_layout_before:
3233             del document.body[layout_before:i]
3234             i = layout_before
3235         else:
3236             document.body[i:i] = ["\\end_layout", ""]
3237             i = i + 2
3238
3239         # Find start of layout in the inset and end of inset
3240         j = find_token(document.body, "\\begin_layout", i)
3241         if j == -1:
3242             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3243             return
3244         k = find_end_of_inset(document.body, i)
3245         if k == -1:
3246             document.warning("Malformed LyX document: Missing `\\end_inset'.")
3247             return
3248
3249         # We either need to delete the following \end_layout line, or we need
3250         # to restart the old layout if this inset is not at the paragraph end.
3251         layout_after = find_token(document.body, "\\end_layout", k)
3252         if layout_after == -1:
3253             document.warning("Malformed LyX document: Missing `\\end_layout'.")
3254             return
3255         del_layout_after = True
3256         l = k + 1
3257         while l < layout_after:
3258             if document.body[l] != "":
3259                 del_layout_after = False
3260                 break
3261             l = l + 1
3262         if del_layout_after:
3263             del document.body[k+1:layout_after+1]
3264         else:
3265             document.body[k+1:k+1] = [layout_line, ""]
3266
3267         # delete \begin_layout and \end_inset and replace \begin_inset with
3268         # "\begin_layout XXX". This works because we can only have one
3269         # paragraph in the caption inset: The old \end_layout will be recycled.
3270         del document.body[k]
3271         if document.body[k] == "":
3272             del document.body[k]
3273         del document.body[j]
3274         if document.body[j] == "":
3275             del document.body[j]
3276         document.body[i] = "\\begin_layout %s" % caption_dict[val]
3277         if document.body[i+1] == "":
3278             del document.body[i+1]
3279         i = i + 1
3280
3281
3282 def revert_fragileframe(document):
3283     " Reverts beamer FragileFrame layout to ERT "
3284     
3285     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3286     if document.textclass not in beamer_classes:
3287         return
3288
3289     i = 0
3290     while True:
3291         i = find_token(document.body, "\\begin_layout FragileFrame", i)
3292         if i == -1:
3293             return
3294         # Find end of sequence
3295         j = find_end_of_sequence(document.body, i)
3296         if j == -1:
3297             document.warning("Malformed lyx document. Cannot find end of FragileFrame sequence!")
3298             i = i + 1
3299             continue
3300         endseq = j
3301         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{frame}")
3302         esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{frame}")
3303         endseq = endseq + len(esubst) - len(document.body[j : j])
3304         if document.body[j] == "\\end_deeper":
3305             document.body[j : j] = ["\\end_deeper", ""] + esubst
3306         else:
3307             document.body[j : j] = esubst
3308         for q in range(i, j):
3309             if document.body[q] == "\\begin_layout FragileFrame":
3310                 document.body[q] = "\\begin_layout %s" % document.default_layout
3311         r = i
3312         while r < j:
3313             if document.body[r] == "\\begin_deeper":
3314                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3315                 if s != -1:
3316                     document.body[r] = ""
3317                     document.body[s] = ""
3318                     r = s
3319                     continue
3320             r = r + 1
3321         for p in range(1, 5):
3322             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, j)
3323             if arg != -1:
3324                 if p == 1:
3325                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3326                     endPlain = find_end_of_layout(document.body, beginPlain)
3327                     endInset = find_end_of_inset(document.body, arg)
3328                     content = document.body[beginPlain + 1 : endPlain]
3329                     # Adjust range end
3330                     j = j - len(document.body[arg : endInset + 1])
3331                     # Remove arg inset
3332                     del document.body[arg : endInset + 1]
3333                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3334                 elif p == 2:
3335                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3336                     endPlain = find_end_of_layout(document.body, beginPlain)
3337                     endInset = find_end_of_inset(document.body, arg)
3338                     content = document.body[beginPlain + 1 : endPlain]
3339                     # Adjust range end
3340                     j = j - len(document.body[arg : endInset + 1])
3341                     # Remove arg inset
3342                     del document.body[arg : endInset + 1]
3343                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3344                 elif p == 3:
3345                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3346                     endPlain = find_end_of_layout(document.body, beginPlain)
3347                     endInset = find_end_of_inset(document.body, arg)
3348                     content = document.body[beginPlain + 1 : endPlain]
3349                     # Adjust range end
3350                     j = j - len(document.body[arg : endInset + 1])
3351                     # Remove arg inset
3352                     del document.body[arg : endInset + 1]
3353                     subst += put_cmd_in_ert("[fragile,") + content + put_cmd_in_ert("]")
3354                 elif p == 4:
3355                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3356                     endPlain = find_end_of_layout(document.body, beginPlain)
3357                     endInset = find_end_of_inset(document.body, arg)
3358                     content = document.body[beginPlain + 1 : endPlain]
3359                     # Adjust range end
3360                     j = j - len(document.body[arg : endInset + 1])
3361                     # Remove arg inset
3362                     del document.body[arg : endInset + 1]
3363                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3364             elif p == 3:
3365                 subst += put_cmd_in_ert("[fragile]")
3366                     
3367         document.body[i : i + 1] = subst
3368         i = j
3369
3370
3371 def revert_newframes(document):
3372     " Reverts beamer Frame and PlainFrame layouts to old forms "
3373     
3374     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3375     if document.textclass not in beamer_classes:
3376         return
3377
3378     frame_dict = {
3379         "Frame" : "BeginFrame",
3380         "PlainFrame" : "BeginPlainFrame",
3381         }
3382
3383     rx = re.compile(r'^\\begin_layout (\S+)$')
3384     i = 0
3385     while True:
3386         i = find_token(document.body, "\\begin_layout", i)
3387         if i == -1:
3388             return
3389
3390         m = rx.match(document.body[i])
3391         val = ""
3392         if m:
3393             val = m.group(1)
3394         if val not in frame_dict.keys():
3395             i = i + 1
3396             continue
3397         # Find end of sequence
3398         j = find_end_of_sequence(document.body, i)
3399         if j == -1:
3400             document.warning("Malformed lyx document. Cannot find end of Frame sequence!")
3401             i = i + 1
3402             continue
3403         endseq = j
3404         subst = ["\\begin_layout %s" % frame_dict[val]]
3405         esubst = ["\\end_layout", "", "\\begin_layout EndFrame", "", "\\end_layout"]
3406         endseq = endseq + len(esubst) - len(document.body[j : j])
3407         if document.body[j] == "\\end_deeper":
3408             document.body[j : j] = ["\\end_deeper", ""] + esubst
3409         else:
3410             document.body[j : j] = esubst
3411         for q in range(i, j):
3412             if document.body[q] == "\\begin_layout %s" % val:
3413                 document.body[q] = "\\begin_layout %s" % document.default_layout
3414         r = i
3415         while r < j:
3416             if document.body[r] == "\\begin_deeper":
3417                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3418                 if s != -1:
3419                     document.body[r] = ""
3420                     document.body[s] = ""
3421                     r = s
3422                     continue
3423             r = r + 1
3424         l = find_end_of_layout(document.body, i)
3425         for p in range(1, 5):
3426             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, l)
3427             if arg != -1:
3428                 if p == 1:
3429                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3430                     endPlain = find_end_of_layout(document.body, beginPlain)
3431                     endInset = find_end_of_inset(document.body, arg)
3432                     content = document.body[beginPlain + 1 : endPlain]
3433                     # Adjust range end
3434                     l = l - len(document.body[arg : endInset + 1])
3435                     # Remove arg inset
3436                     del document.body[arg : endInset + 1]
3437                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3438                 elif p == 2:
3439                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3440                     endPlain = find_end_of_layout(document.body, beginPlain)
3441                     endInset = find_end_of_inset(document.body, arg)
3442                     content = document.body[beginPlain + 1 : endPlain]
3443                     # Adjust range end
3444                     l = l - len(document.body[arg : endInset + 1])
3445                     # Remove arg inset
3446                     del document.body[arg : endInset + 1]
3447                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3448                 elif p == 3:
3449                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3450                     endPlain = find_end_of_layout(document.body, beginPlain)
3451                     endInset = find_end_of_inset(document.body, arg)
3452                     content = document.body[beginPlain + 1 : endPlain]
3453                     # Adjust range end
3454                     l = l - len(document.body[arg : endInset + 1])
3455                     # Remove arg inset
3456                     del document.body[arg : endInset + 1]
3457                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3458                 elif p == 4:
3459                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3460                     endPlain = find_end_of_layout(document.body, beginPlain)
3461                     endInset = find_end_of_inset(document.body, arg)
3462                     content = document.body[beginPlain + 1 : endPlain]
3463                     # Adjust range end
3464                     l = l - len(document.body[arg : endInset + 1])
3465                     # Remove arg inset
3466                     del document.body[arg : endInset + 1]
3467                     subst += content
3468                     
3469         document.body[i : i + 1] = subst
3470         i = j
3471
3472
3473 ##
3474 # Conversion hub
3475 #
3476
3477 supported_versions = ["2.1.0","2.1"]
3478 convert = [
3479            [414, []],
3480            [415, [convert_undertilde]],
3481            [416, []],
3482            [417, [convert_japanese_encodings]],
3483            [418, []],
3484            [419, []],
3485            [420, [convert_biblio_style]],
3486            [421, [convert_longtable_captions]],
3487            [422, [convert_use_packages]],
3488            [423, [convert_use_mathtools]],
3489            [424, [convert_cite_engine_type]],
3490            [425, []],
3491            [426, []],
3492            [427, []],
3493            [428, [convert_cell_rotation]],
3494            [429, [convert_table_rotation]],
3495            [430, [convert_listoflistings]],
3496            [431, [convert_use_amssymb]],
3497            [432, []],
3498            [433, [convert_armenian]],
3499            [434, []],
3500            [435, []],
3501            [436, []],
3502            [437, []],
3503            [438, []],
3504            [439, []],
3505            [440, []],
3506            [441, [convert_mdnomath]],
3507            [442, []],
3508            [443, []],
3509            [444, []],
3510            [445, []],
3511            [446, [convert_latexargs]],
3512            [447, [convert_IEEEtran, convert_AASTeX, convert_AGUTeX, convert_IJMP, convert_SIGPLAN, convert_SIGGRAPH, convert_EuropeCV, convert_Initials, convert_ModernCV]],
3513            [448, [convert_literate]],
3514            [449, []],
3515            [450, []],
3516            [451, [convert_beamerargs, convert_againframe_args, convert_corollary_args, convert_quote_args]],
3517            [452, [convert_beamerblocks]],
3518            [453, [convert_use_stmaryrd]],
3519            [454, [convert_overprint]],
3520            [455, []],
3521            [456, [convert_epigraph]],
3522            [457, [convert_use_stackrel]],
3523            [458, [convert_captioninsets, convert_captionlayouts]],
3524            [459, []]
3525           ]
3526
3527 revert =  [
3528            [458, [revert_fragileframe, revert_newframes]],
3529            [457, [revert_captioninsets, revert_captionlayouts]],
3530            [456, [revert_use_stackrel]],
3531            [455, [revert_epigraph]],
3532            [454, [revert_frametitle]],
3533            [453, [revert_overprint]],
3534            [452, [revert_use_stmaryrd]],
3535            [451, [revert_beamerblocks]],
3536            [450, [revert_beamerargs, revert_beamerargs2, revert_beamerargs3, revert_beamerflex]],
3537            [449, [revert_garamondx, revert_garamondx_newtxmath]],
3538            [448, [revert_itemargs]],
3539            [447, [revert_literate]],
3540            [446, [revert_IEEEtran, revert_AASTeX, revert_AGUTeX, revert_IJMP, revert_SIGPLAN, revert_SIGGRAPH, revert_EuropeCV, revert_Initials, revert_ModernCV]],
3541            [445, [revert_latexargs]],
3542            [444, [revert_uop]],
3543            [443, [revert_biolinum]],
3544            [442, []],
3545            [441, [revert_newtxmath]],
3546            [440, [revert_mdnomath]],
3547            [439, [revert_mathfonts]],
3548            [438, [revert_minionpro]],
3549            [437, [revert_ipadeco, revert_ipachar]],
3550            [436, [revert_texgyre]],
3551            [435, [revert_mathdesign]],
3552            [434, [revert_txtt]],
3553            [433, [revert_libertine]],
3554            [432, [revert_armenian]],
3555            [431, [revert_languages, revert_ancientgreek]],
3556            [430, [revert_use_amssymb]],
3557            [429, [revert_listoflistings]],
3558            [428, [revert_table_rotation]],
3559            [427, [revert_cell_rotation]],
3560            [426, [revert_tipa]],
3561            [425, [revert_verbatim]],
3562            [424, [revert_cancel]],
3563            [423, [revert_cite_engine_type]],
3564            [422, [revert_use_mathtools]],
3565            [421, [revert_use_packages]],
3566            [420, [revert_longtable_captions]],
3567            [419, [revert_biblio_style]],
3568            [418, [revert_australian]],
3569            [417, [revert_justification]],
3570            [416, [revert_japanese_encodings]],
3571            [415, [revert_negative_space, revert_math_spaces]],
3572            [414, [revert_undertilde]],
3573            [413, [revert_visible_space]]
3574           ]
3575
3576
3577 if __name__ == "__main__":
3578     pass