]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_1.py
d921cbb13a566a03a4699f02427e42803cf5fe86
[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 revert_IEEEtran(document):
1460   '''
1461   Reverts InsetArgument of
1462   Page headings
1463   Biography
1464   Biography without photo
1465   to TeX-code
1466   '''
1467   if document.textclass == "IEEEtran":
1468     i = 0
1469     j = 0
1470     k = 0
1471     while True:
1472       if i != -1:
1473         i = find_token(document.body, "\\begin_layout Page headings", i)
1474       if i != -1:
1475         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1476         i = i + 1
1477       if j != -1:
1478         j = find_token(document.body, "\\begin_layout Biography without photo", j)
1479       if j != -1:
1480         revert_Argument_to_TeX_brace(document, j, 1, 1, True)
1481         j = j + 1
1482       if k != -1:
1483         k = find_token(document.body, "\\begin_layout Biography", k)
1484         kA = find_token(document.body, "\\begin_layout Biography without photo", k)
1485         if k == kA and k != -1:
1486           k = k + 1
1487           continue
1488       if k != -1:
1489         # start with the second argument, therefore 2
1490         revert_Argument_to_TeX_brace(document, k, 2, 2, True)
1491         k = k + 1
1492       if i == -1 and j == -1 and k == -1:
1493         return
1494
1495
1496 def convert_TeX_brace_to_Argument(document, line, n, nmax, inset, environment):
1497     '''
1498     Converts TeX code for mandatory arguments to an InsetArgument
1499     The conversion of TeX code for optional arguments must be done with another routine
1500     !!! Be careful if the braces are different in your case as expected here:
1501     - "}{" separates mandatory arguments of commands
1502     - "}" + "{" separates mandatory arguments of commands
1503     - "}" + " " + "{" separates mandatory arguments of commands
1504     - { and } surround a mandatory argument of an environment
1505     usage:
1506     convert_TeX_brace_to_Argument(document, LineOfBeginLayout/Inset, StartArgument, EndArgument, isInset, isEnvironment)
1507     LineOfBeginLayout/Inset is the line  of the \begin_layout or \begin_inset statement
1508     StartArgument is the number of the first ERT that needs to be converted
1509     EndArgument is the number of the last ERT that needs to be converted
1510     isInset must be true, if braces inside an InsetLayout needs to be converted
1511     isEnvironment must be true, if the layout is for a LaTeX environment
1512     
1513     Todo: this routine can currently handle only one mandatory argument of environments
1514     '''
1515     lineERT = line
1516     endn = line
1517     loop = 1
1518     while lineERT != -1 and n < nmax + 1:
1519       lineERT = find_token(document.body, "\\begin_inset ERT", lineERT)
1520       if environment == False and lineERT != -1:
1521         bracePair = find_token(document.body, "}{", lineERT)
1522         # assure that the "}{" is in this ERT
1523         if bracePair == lineERT + 5:
1524           end = find_token(document.body, "\\end_inset", bracePair)
1525           document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
1526           if loop == 1:
1527             # in the case that n > 1 we have optional arguments before
1528             # therefore detect them if any
1529             if n > 1:
1530               # first check if there is an argument
1531               lineArg = find_token(document.body, "\\begin_inset Argument", line)
1532               if lineArg < lineERT and lineArg != -1:
1533                 # we have an argument, so now search backwards for its end
1534                 # we must now assure that we don't find other insets like e.g. a newline
1535                 endInsetArg = lineERT
1536                 endLayoutArg = endInsetArg
1537                 while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
1538                   endInsetArg = endInsetArg - 1
1539                   endLayoutArg = endInsetArg
1540                   endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
1541                   endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
1542                 line = endInsetArg + 1
1543             if inset == False:
1544               document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1545             else:
1546               document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1547           else:
1548             document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1549           n = n + 1
1550           endn = end
1551           loop = loop + 1
1552         # now check the case that we have "}" + "{" in two ERTs
1553         else:
1554           endBrace = find_token(document.body, "}", lineERT)
1555           if endBrace == lineERT + 5:
1556             beginBrace = find_token(document.body, "{", endBrace)
1557             # assure that the ERTs are consecutive (11 or 12 depending if there is a space between the ERTs or not)
1558             if beginBrace == endBrace + 11 or beginBrace == endBrace + 12:
1559               end = find_token(document.body, "\\end_inset", beginBrace)
1560               document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
1561               if loop == 1:
1562                 # in the case that n > 1 we have optional arguments before
1563                 # therefore detect them if any
1564                 if n > 1:
1565                   # first check if there is an argument
1566                   lineArg = find_token(document.body, "\\begin_inset Argument", line)
1567                   if lineArg < lineERT and lineArg != -1:
1568                     # we have an argument, so now search backwards for its end
1569                     # we must now assure that we don't find other insets like e.g. a newline
1570                     endInsetArg = lineERT
1571                     endLayoutArg = endInsetArg
1572                     while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
1573                       endInsetArg = endInsetArg - 1
1574                       endLayoutArg = endInsetArg
1575                       endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
1576                       endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
1577                     line = endInsetArg + 1
1578                 if inset == False:
1579                   document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1580                 else:
1581                   document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1582               else:
1583                 document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1584               n = n + 1
1585               loop = loop + 1
1586               # set the line where the next argument will be inserted
1587               if beginBrace == endBrace + 11:
1588                 endn = end - 11
1589               else:
1590                 endn = end - 12
1591           else:
1592             lineERT = lineERT + 1
1593       if environment == True and lineERT != -1:
1594         opening = find_token(document.body, "{", lineERT)
1595         if opening == lineERT + 5: # assure that the "{" is in this ERT
1596           end = find_token(document.body, "\\end_inset", opening)
1597           document.body[lineERT : end + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1598           n = n + 1
1599           lineERT2 = find_token(document.body, "\\begin_inset ERT", lineERT)
1600           closing = find_token(document.body, "}", lineERT2)
1601           if closing == lineERT2 + 5: # assure that the "}" is in this ERT
1602             end2 = find_token(document.body, "\\end_inset", closing)
1603             document.body[lineERT2 : end2 + 1] = ["\\end_layout", "", "\\end_inset"]
1604         else:
1605           lineERT = lineERT + 1
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 InsetArgument of MarkBoth 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 MarkBoth 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 InsetArgument of Flex CRcat 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 Flex CRcat 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_Initials(document):
1863   " Reverts InsetArgument of Initial to TeX-code "
1864   i = 0
1865   while True:
1866     if i != -1:
1867       i = find_token(document.body, "\\begin_layout Initial", i)
1868     if i != -1:
1869       # first arg (optional) and second arg (first mandatory) are supported in LyX 2.0.x
1870       revert_Argument_to_TeX_brace(document, i, 3, 3, False)
1871       i = i + 1
1872     if i == -1:
1873       return
1874
1875
1876 def convert_Initials(document):
1877   " Converts ERT of Initial to InsetArgument "
1878   i = 0
1879   while True:
1880     if i != -1:
1881       i = find_token(document.body, "\\begin_layout Initial", i)
1882     if i != -1:
1883       convert_TeX_brace_to_Argument(document, i, 3, 3, False, False)
1884       i = i + 1
1885     if i == -1:
1886       return
1887
1888
1889 def revert_literate(document):
1890     " Revert Literate document to old format "
1891     if del_token(document.header, "noweb", 0):
1892       document.textclass = "literate-" + document.textclass
1893       i = 0
1894       while True:
1895         i = find_token(document.body, "\\begin_layout Chunk", i)
1896         if i == -1:
1897           break
1898         document.body[i] = "\\begin_layout Scrap"
1899         i = i + 1
1900
1901
1902 def convert_literate(document):
1903     " Convert Literate document to new format"
1904     i = find_token(document.header, "\\textclass", 0)    
1905     if (i != -1) and "literate-" in document.header[i]:
1906       document.textclass = document.header[i].replace("\\textclass literate-", "")
1907       j = find_token(document.header, "\\begin_modules", 0)
1908       if (j != -1):
1909         document.header.insert(j + 1, "noweb")
1910       else:
1911         document.header.insert(i + 1, "\\end_modules")
1912         document.header.insert(i + 1, "noweb")
1913         document.header.insert(i + 1, "\\begin_modules")
1914       i = 0
1915       while True:
1916         i = find_token(document.body, "\\begin_layout Scrap", i)
1917         if i == -1:
1918           break
1919         document.body[i] = "\\begin_layout Chunk"
1920         i = i + 1
1921
1922
1923 def revert_itemargs(document):
1924     " Reverts \\item arguments to TeX-code "
1925     i = 0
1926     while True:
1927         i = find_token(document.body, "\\begin_inset Argument item:", i)
1928         if i == -1:
1929             return
1930         j = find_end_of_inset(document.body, i)
1931         # Find containing paragraph layout
1932         parent = get_containing_layout(document.body, i)
1933         if parent == False:
1934             document.warning("Malformed lyx document: Can't find parent paragraph layout")
1935             i = i + 1
1936             continue
1937         parbeg = parent[3]
1938         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
1939         endPlain = find_end_of_layout(document.body, beginPlain)
1940         content = document.body[beginPlain + 1 : endPlain]
1941         del document.body[i:j+1]
1942         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
1943         document.body[parbeg : parbeg] = subst
1944         i = i + 1
1945
1946
1947 def revert_garamondx_newtxmath(document):
1948     " Revert native garamond newtxmath definition to LaTeX " 
1949
1950     i = find_token(document.header, "\\font_math", 0)
1951     if i == -1:
1952        return
1953     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1954         val = get_value(document.header, "\\font_math", i)
1955         if val == "garamondx-ntxm":
1956             add_to_preamble(document, "\\usepackage[garamondx]{newtxmath}")
1957             document.header[i] = "\\font_math auto"
1958
1959
1960 def revert_garamondx(document):
1961     " Revert native garamond font definition to LaTeX " 
1962
1963     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1964         i = find_token(document.header, "\\font_roman garamondx", 0)
1965         if i != -1:
1966             osf = False
1967             j = find_token(document.header, "\\font_osf true", 0)
1968             if j != -1:
1969                 osf = True
1970             preamble = "\\usepackage"
1971             if osf:
1972                 preamble += "[osfI]"
1973             preamble += "{garamondx}"
1974             add_to_preamble(document, [preamble])
1975             document.header[i] = "\\font_roman default"
1976
1977
1978 def convert_beamerargs(document):
1979     " Converts beamer arguments to new layout "
1980     
1981     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
1982     if document.textclass not in beamer_classes:
1983         return
1984
1985     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
1986     list_layouts = ["Itemize", "Enumerate", "Description"]
1987     rx = re.compile(r'^\\begin_inset Argument (\d+)$')
1988
1989     i = 0
1990     while True:
1991         i = find_token(document.body, "\\begin_inset Argument", i)
1992         if i == -1:
1993             return
1994         # Find containing paragraph layout
1995         parent = get_containing_layout(document.body, i)
1996         if parent == False:
1997             document.warning("Malformed lyx document: Can't find parent paragraph layout")
1998             i = i + 1
1999             continue
2000         parbeg = parent[1]
2001         parend = parent[2]
2002         layoutname = parent[0]
2003         for p in range(parbeg, parend):
2004             if layoutname in shifted_layouts:
2005                 m = rx.match(document.body[p])
2006                 if m:
2007                     argnr = int(m.group(1))
2008                     argnr += 1
2009                     document.body[p] = "\\begin_inset Argument %d" % argnr
2010             if layoutname == "AgainFrame":
2011                 m = rx.match(document.body[p])
2012                 if m:
2013                     document.body[p] = "\\begin_inset Argument 3"
2014                     if document.body[p + 4] == "\\begin_inset ERT":
2015                         if document.body[p + 9].startswith("<"):
2016                             # This is an overlay specification
2017                             # strip off the <
2018                             document.body[p + 9] = document.body[p + 9][1:]
2019                             if document.body[p + 9].endswith(">"):
2020                                 # strip off the >
2021                                 document.body[p + 9] = document.body[p + 9][:-1]
2022                                 # Shift this one
2023                                 document.body[p] = "\\begin_inset Argument 2"
2024             if layoutname in list_layouts:
2025                 m = rx.match(document.body[p])
2026                 if m:
2027                     if m.group(1) == "1":
2028                         if document.body[p + 4] == "\\begin_inset ERT":
2029                             if document.body[p + 9].startswith("<"):
2030                                 # This is an overlay specification
2031                                 # strip off the <
2032                                 document.body[p + 9] = document.body[p + 9][1:]
2033                                 if document.body[p + 9].endswith(">"):
2034                                     # strip off the >
2035                                     document.body[p + 9] = document.body[p + 9][:-1]
2036                         elif layoutname != "Itemize":
2037                             # Shift this one
2038                             document.body[p] = "\\begin_inset Argument 2"
2039         i = i + 1
2040
2041
2042 def convert_againframe_args(document):
2043     " Converts beamer AgainFrame to new layout "
2044
2045     # FIXME: This currently only works if the arguments are in one single ERT
2046     
2047     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2048     if document.textclass not in beamer_classes:
2049         return
2050    
2051     i = 0
2052     while True:
2053         i = find_token(document.body, "\\begin_layout AgainFrame", i)
2054         if i == -1:
2055             break
2056         parent = get_containing_layout(document.body, i)
2057         if parent[1] != i:
2058             document.warning("Wrong parent layout!")
2059         j = parent[2]
2060         parbeg = parent[3]
2061         if i != -1:
2062             if document.body[parbeg] == "\\begin_inset ERT":
2063                 ertcont = parbeg + 5
2064                 if document.body[ertcont].startswith("[<"):
2065                     # This is a default overlay specification
2066                     # strip off the [<
2067                     document.body[ertcont] = document.body[ertcont][2:]
2068                     if document.body[ertcont].endswith(">]"):
2069                         # strip off the >]
2070                         document.body[ertcont] = document.body[ertcont][:-2]
2071                     elif document.body[ertcont].endswith("]"):
2072                         # divide the args
2073                         tok = document.body[ertcont].find('>][')
2074                         if tok != -1:
2075                             subst = [document.body[ertcont][:tok],
2076                                      '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2077                                      'status collapsed', '', '\\begin_layout Plain Layout',
2078                                      document.body[ertcont][tok + 3:-1]]
2079                             document.body[ertcont : ertcont + 1] = subst
2080                      # Convert to ArgInset
2081                     document.body[parbeg] = "\\begin_inset Argument 2"
2082                     i = j
2083                     continue
2084                 elif document.body[ertcont].startswith("<"):
2085                     # This is an overlay specification
2086                     # strip off the <
2087                     document.body[ertcont] = document.body[ertcont][1:]
2088                     if document.body[ertcont].endswith(">"):
2089                         # strip off the >
2090                         document.body[ertcont] = document.body[ertcont][:-1]
2091                         # Convert to ArgInset
2092                         document.body[parbeg] = "\\begin_inset Argument 1"
2093                     elif document.body[ertcont].endswith(">]"):
2094                         # divide the args
2095                         tok = document.body[ertcont].find('>[<')
2096                         if tok != -1:
2097                            document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2098                                                            '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2099                                                            'status collapsed', '', '\\begin_layout Plain Layout',
2100                                                            document.body[ertcont][tok + 3:-2]]
2101                         # Convert to ArgInset
2102                         document.body[parbeg] = "\\begin_inset Argument 1"
2103                     elif document.body[ertcont].endswith("]"):
2104                         # divide the args
2105                         tok = document.body[ertcont].find('>[<')
2106                         if tok != -1:
2107                            # divide the args
2108                            tokk = document.body[ertcont].find('>][')
2109                            if tokk != -1:
2110                                document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2111                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2112                                                                'status collapsed', '', '\\begin_layout Plain Layout',
2113                                                                document.body[ertcont][tok + 3:tokk],
2114                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2115                                                                'status collapsed', '', '\\begin_layout Plain Layout',
2116                                                                document.body[ertcont][tokk + 3:-1]]
2117                         else:
2118                             tokk = document.body[ertcont].find('>[')
2119                             if tokk != -1:
2120                                 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tokk],
2121                                                                 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2122                                                                 'status collapsed', '', '\\begin_layout Plain Layout',
2123                                                                 document.body[ertcont][tokk + 2:-1]]
2124                         # Convert to ArgInset
2125                         document.body[parbeg] = "\\begin_inset Argument 1"
2126                     i = j
2127                     continue
2128                 elif document.body[ertcont].startswith("["):
2129                     # This is an ERT option
2130                     # strip off the [
2131                     document.body[ertcont] = document.body[ertcont][1:]
2132                     if document.body[ertcont].endswith("]"):
2133                         # strip off the ]
2134                         document.body[ertcont] = document.body[ertcont][:-1]
2135                         # Convert to ArgInset
2136                         document.body[parbeg] = "\\begin_inset Argument 3"
2137                     i = j
2138                     continue
2139         i = j
2140
2141
2142 def convert_corollary_args(document):
2143     " Converts beamer corrolary-style ERT arguments native InsetArgs "
2144     
2145     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2146     if document.textclass not in beamer_classes:
2147         return
2148    
2149     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2150     for lay in corollary_layouts:
2151         i = 0
2152         while True:
2153             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2154             if i == -1:
2155                 break
2156             parent = get_containing_layout(document.body, i)
2157             if parent[1] != i:
2158                 document.warning("Wrong parent layout!")
2159             j = parent[2]
2160             parbeg = parent[3]
2161             if i != -1:
2162                 if document.body[parbeg] == "\\begin_inset ERT":
2163                     ertcont = parbeg + 5
2164                     if document.body[ertcont].startswith("<"):
2165                         # This is an overlay specification
2166                         # strip off the <
2167                         document.body[ertcont] = document.body[ertcont][1:]
2168                         if document.body[ertcont].endswith(">"):
2169                             # strip off the >
2170                             document.body[ertcont] = document.body[ertcont][:-1]
2171                         elif document.body[ertcont].endswith("]"):
2172                             # divide the args
2173                             tok = document.body[ertcont].find('>[')
2174                             if tok != -1:
2175                                 subst = [document.body[ertcont][:tok],
2176                                          '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2177                                          'status collapsed', '', '\\begin_layout Plain Layout',
2178                                          document.body[ertcont][tok + 2:-1]]
2179                                 document.body[ertcont : ertcont + 1] = subst
2180                         # Convert to ArgInset
2181                         document.body[parbeg] = "\\begin_inset Argument 1"
2182                         i = j
2183                         continue
2184                     elif document.body[ertcont].startswith("["):
2185                         # This is an ERT option
2186                         # strip off the [
2187                         document.body[ertcont] = document.body[ertcont][1:]
2188                         if document.body[ertcont].endswith("]"):
2189                             # strip off the ]
2190                             document.body[ertcont] = document.body[ertcont][:-1]
2191                         # Convert to ArgInset
2192                         document.body[parbeg] = "\\begin_inset Argument 2"
2193                     i = j
2194                     continue
2195             i = j
2196
2197
2198
2199 def convert_quote_args(document):
2200     " Converts beamer quote style ERT args to native InsetArgs "
2201     
2202     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2203     if document.textclass not in beamer_classes:
2204         return
2205    
2206     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2207     for lay in quote_layouts:
2208         i = 0
2209         while True:
2210             i = find_token(document.body, "\\begin_layout " + lay, i)
2211             if i == -1:
2212                 break
2213             parent = get_containing_layout(document.body, i)
2214             if parent[1] != i:
2215                 document.warning("Wrong parent layout!")
2216             j = parent[2]
2217             parbeg = parent[3]
2218             if i != -1:
2219                 if document.body[parbeg] == "\\begin_inset ERT":
2220                     if document.body[i + 6].startswith("<"):
2221                         # This is an overlay specification
2222                         # strip off the <
2223                         document.body[i + 6] = document.body[i + 6][1:]
2224                         if document.body[i + 6].endswith(">"):
2225                             # strip off the >
2226                             document.body[i + 6] = document.body[i + 6][:-1]
2227                             # Convert to ArgInset
2228                             document.body[i + 1] = "\\begin_inset Argument 1"
2229             i = j
2230
2231
2232 def revert_beamerargs(document):
2233     " Reverts beamer arguments to old layout "
2234     
2235     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2236     if document.textclass not in beamer_classes:
2237         return
2238
2239     i = 0
2240     list_layouts = ["Itemize", "Enumerate", "Description"]
2241     headings = ["Part", "Section", "Section*", "Subsection", "Subsection*",
2242                 "Subsubsection", "Subsubsection*", "FrameSubtitle", "NoteItem"]
2243     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2244     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2245     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2246
2247     while True:
2248         i = find_token(document.body, "\\begin_inset Argument", i)
2249         if i == -1:
2250             return
2251         # Find containing paragraph layout
2252         parent = get_containing_layout(document.body, i)
2253         if parent == False:
2254             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2255             i = i + 1
2256             continue
2257         parbeg = parent[1]
2258         parend = parent[2]
2259         realparbeg = parent[3]
2260         layoutname = parent[0]
2261         realparend = parend
2262         for p in range(parbeg, parend):
2263             if p >= realparend:
2264                 i = realparend
2265                 break
2266             if layoutname in headings:
2267                 m = rx.match(document.body[p])
2268                 if m:
2269                     argnr = m.group(1)
2270                     if argnr == "1":
2271                         # Find containing paragraph layout
2272                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2273                         endPlain = find_end_of_layout(document.body, beginPlain)
2274                         endInset = find_end_of_inset(document.body, p)
2275                         argcontent = document.body[beginPlain + 1 : endPlain]
2276                         # Adjust range end
2277                         realparend = realparend - len(document.body[p : endInset + 1])
2278                         # Remove arg inset
2279                         del document.body[p : endInset + 1]
2280                         if layoutname == "FrameSubtitle":
2281                             pre = put_cmd_in_ert("\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2282                         elif layoutname == "NoteItem":
2283                             pre = put_cmd_in_ert("\\note<") + argcontent + put_cmd_in_ert(">[item]")
2284                         elif layoutname.endswith('*'):
2285                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower()[:-1] + "<") + argcontent + put_cmd_in_ert(">*")
2286                         else:
2287                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2288                         secarg = find_token(document.body, "\\begin_inset Argument 2", parbeg, parend)
2289                         if secarg != -1:
2290                             # Find containing paragraph layout
2291                             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", secarg)
2292                             endPlain = find_end_of_layout(document.body, beginPlain)
2293                             endInset = find_end_of_inset(document.body, secarg)
2294                             argcontent = document.body[beginPlain + 1 : endPlain]
2295                             # Adjust range end
2296                             realparend = realparend - len(document.body[secarg : endInset + 1])
2297                             del document.body[secarg : endInset + 1]
2298                             pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2299                         pre += put_cmd_in_ert("{")
2300                         document.body[parbeg] = "\\begin_layout Standard"
2301                         document.body[realparbeg : realparbeg] = pre
2302                         pe = find_end_of_layout(document.body, parbeg)
2303                         post = put_cmd_in_ert("}")
2304                         document.body[pe : pe] = post
2305                         realparend += len(pre) + len(post)
2306             if layoutname == "AgainFrame":
2307                 m = rx.match(document.body[p])
2308                 if m:
2309                     argnr = m.group(1)
2310                     if argnr == "3":
2311                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2312                         endPlain = find_end_of_layout(document.body, beginPlain)
2313                         endInset = find_end_of_inset(document.body, p)
2314                         content = document.body[beginPlain + 1 : endPlain]
2315                         # Adjust range end
2316                         realparend = realparend - len(document.body[p : endInset + 1])
2317                         # Remove arg inset
2318                         del document.body[p : endInset + 1]
2319                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2320                         document.body[realparbeg : realparbeg] = subst
2321             if layoutname == "Overprint":
2322                 m = rx.match(document.body[p])
2323                 if m:
2324                     argnr = m.group(1)
2325                     if argnr == "1":
2326                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2327                         endPlain = find_end_of_layout(document.body, beginPlain)
2328                         endInset = find_end_of_inset(document.body, p)
2329                         content = document.body[beginPlain + 1 : endPlain]
2330                         # Adjust range end
2331                         realparend = realparend - len(document.body[p : endInset + 1])
2332                         # Remove arg inset
2333                         del document.body[p : endInset + 1]
2334                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2335                         document.body[realparbeg : realparbeg] = subst
2336             if layoutname == "OverlayArea":
2337                 m = rx.match(document.body[p])
2338                 if m:
2339                     argnr = m.group(1)
2340                     if argnr == "2":
2341                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2342                         endPlain = find_end_of_layout(document.body, beginPlain)
2343                         endInset = find_end_of_inset(document.body, p)
2344                         content = document.body[beginPlain + 1 : endPlain]
2345                         # Adjust range end
2346                         realparend = realparend - len(document.body[p : endInset + 1])
2347                         # Remove arg inset
2348                         del document.body[p : endInset + 1]
2349                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2350                         document.body[realparbeg : realparbeg] = subst
2351             if layoutname in list_layouts:
2352                 m = rx.match(document.body[p])
2353                 if m:
2354                     argnr = m.group(1)
2355                     if argnr == "1":
2356                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2357                         endPlain = find_end_of_layout(document.body, beginPlain)
2358                         endInset = find_end_of_inset(document.body, p)
2359                         content = document.body[beginPlain + 1 : endPlain]
2360                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2361                         realparend = realparend + len(subst) - len(content)
2362                         document.body[beginPlain + 1 : endPlain] = subst
2363                     elif argnr == "item:1":
2364                         j = find_end_of_inset(document.body, i)
2365                         # Find containing paragraph layout
2366                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2367                         endPlain = find_end_of_layout(document.body, beginPlain)
2368                         content = document.body[beginPlain + 1 : endPlain]
2369                         del document.body[i:j+1]
2370                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2371                         document.body[realparbeg : realparbeg] = subst
2372                     elif argnr == "item:2":
2373                         j = find_end_of_inset(document.body, i)
2374                         # Find containing paragraph layout
2375                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2376                         endPlain = find_end_of_layout(document.body, beginPlain)
2377                         content = document.body[beginPlain + 1 : endPlain]
2378                         del document.body[i:j+1]
2379                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2380                         document.body[realparbeg : realparbeg] = subst
2381             if layoutname in quote_layouts:
2382                 m = rx.match(document.body[p])
2383                 if m:
2384                     argnr = m.group(1)
2385                     if argnr == "1":
2386                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2387                         endPlain = find_end_of_layout(document.body, beginPlain)
2388                         endInset = find_end_of_inset(document.body, p)
2389                         content = document.body[beginPlain + 1 : endPlain]
2390                         # Adjust range end
2391                         realparend = realparend - len(document.body[p : endInset + 1])
2392                         # Remove arg inset
2393                         del document.body[p : endInset + 1]
2394                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2395                         document.body[realparbeg : realparbeg] = subst
2396             if layoutname in corollary_layouts:
2397                 m = rx.match(document.body[p])
2398                 if m:
2399                     argnr = m.group(1)
2400                     if argnr == "2":
2401                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2402                         endPlain = find_end_of_layout(document.body, beginPlain)
2403                         endInset = find_end_of_inset(document.body, p)
2404                         content = document.body[beginPlain + 1 : endPlain]
2405                         # Adjust range end
2406                         realparend = realparend - len(document.body[p : endInset + 1])
2407                         # Remove arg inset
2408                         del document.body[p : endInset + 1]
2409                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2410                         document.body[realparbeg : realparbeg] = subst
2411         
2412         i = realparend
2413
2414
2415 def revert_beamerargs2(document):
2416     " Reverts beamer arguments to old layout, step 2 "
2417     
2418     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2419     if document.textclass not in beamer_classes:
2420         return
2421
2422     i = 0
2423     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2424     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2425     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2426
2427     while True:
2428         i = find_token(document.body, "\\begin_inset Argument", i)
2429         if i == -1:
2430             return
2431         # Find containing paragraph layout
2432         parent = get_containing_layout(document.body, i)
2433         if parent == False:
2434             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2435             i = i + 1
2436             continue
2437         parbeg = parent[1]
2438         parend = parent[2]
2439         realparbeg = parent[3]
2440         layoutname = parent[0]
2441         realparend = parend
2442         for p in range(parbeg, parend):
2443             if p >= realparend:
2444                 i = realparend
2445                 break
2446             if layoutname in shifted_layouts:
2447                 m = rx.match(document.body[p])
2448                 if m:
2449                     argnr = m.group(1)
2450                     if argnr == "2":
2451                         document.body[p] = "\\begin_inset Argument 1"       
2452             if layoutname in corollary_layouts:
2453                 m = rx.match(document.body[p])
2454                 if m:
2455                     argnr = m.group(1)
2456                     if argnr == "1":
2457                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2458                         endPlain = find_end_of_layout(document.body, beginPlain)
2459                         endInset = find_end_of_inset(document.body, p)
2460                         content = document.body[beginPlain + 1 : endPlain]
2461                         # Adjust range end
2462                         realparend = realparend - len(document.body[p : endInset + 1])
2463                         # Remove arg inset
2464                         del document.body[p : endInset + 1]
2465                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2466                         document.body[realparbeg : realparbeg] = subst
2467             if layoutname == "OverlayArea":
2468                 m = rx.match(document.body[p])
2469                 if m:
2470                     argnr = m.group(1)
2471                     if argnr == "1":
2472                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2473                         endPlain = find_end_of_layout(document.body, beginPlain)
2474                         endInset = find_end_of_inset(document.body, p)
2475                         content = document.body[beginPlain + 1 : endPlain]
2476                         # Adjust range end
2477                         realparend = realparend - len(document.body[p : endInset + 1])
2478                         # Remove arg inset
2479                         del document.body[p : endInset + 1]
2480                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2481                         document.body[realparbeg : realparbeg] = subst
2482             if layoutname == "AgainFrame":
2483                 m = rx.match(document.body[p])
2484                 if m:
2485                     argnr = m.group(1)
2486                     if argnr == "2":
2487                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2488                         endPlain = find_end_of_layout(document.body, beginPlain)
2489                         endInset = find_end_of_inset(document.body, p)
2490                         content = document.body[beginPlain + 1 : endPlain]
2491                         # Adjust range end
2492                         realparend = realparend - len(document.body[p : endInset + 1])
2493                         # Remove arg inset
2494                         del document.body[p : endInset + 1]
2495                         subst = put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
2496                         document.body[realparbeg : realparbeg] = subst
2497         i = realparend
2498
2499
2500 def revert_beamerargs3(document):
2501     " Reverts beamer arguments to old layout, step 3 "
2502     
2503     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2504     if document.textclass not in beamer_classes:
2505         return
2506
2507     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2508     i = 0
2509     while True:
2510         i = find_token(document.body, "\\begin_inset Argument", i)
2511         if i == -1:
2512             return
2513         # Find containing paragraph layout
2514         parent = get_containing_layout(document.body, i)
2515         if parent == False:
2516             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2517             i = i + 1
2518             continue
2519         parbeg = parent[1]
2520         parend = parent[2]
2521         realparbeg = parent[3]
2522         layoutname = parent[0]
2523         realparend = parend
2524         for p in range(parbeg, parend):
2525             if p >= realparend:
2526                 i = realparend
2527                 break
2528             if layoutname == "AgainFrame":
2529                 m = rx.match(document.body[p])
2530                 if m:
2531                     argnr = m.group(1)
2532                     if argnr == "1":
2533                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2534                         endPlain = find_end_of_layout(document.body, beginPlain)
2535                         endInset = find_end_of_inset(document.body, p)
2536                         content = document.body[beginPlain + 1 : endPlain]
2537                         # Adjust range end
2538                         realparend = realparend - len(document.body[p : endInset + 1])
2539                         # Remove arg inset
2540                         del document.body[p : endInset + 1]
2541                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2542                         document.body[realparbeg : realparbeg] = subst
2543         i = realparend
2544
2545
2546 def revert_beamerflex(document):
2547     " Reverts beamer Flex insets "
2548     
2549     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2550     if document.textclass not in beamer_classes:
2551         return
2552
2553     new_flexes = {"Bold" : "\\textbf", "Emphasize" : "\\emph", "Only" : "\\only",
2554                   "Uncover" : "\\uncover", "Visible" : "\\visible",
2555                   "Invisible" : "\\invisible", "Alternative" : "\\alt",
2556                   "Beamer_Note" : "\\note"}
2557     old_flexes = {"Alert" : "\\alert", "Structure" : "\\structure"}
2558     rx = re.compile(r'^\\begin_inset Flex (.+)$')
2559
2560     i = 0
2561     while True:
2562         i = find_token(document.body, "\\begin_inset Flex", i)
2563         if i == -1:
2564             return
2565         m = rx.match(document.body[i])
2566         if m:
2567             flextype = m.group(1)
2568             z = find_end_of_inset(document.body, i)
2569             if z == -1:
2570                 document.warning("Can't find end of Flex " + flextype + " inset.")
2571                 i += 1
2572                 continue
2573             if flextype in new_flexes:
2574                 pre = put_cmd_in_ert(new_flexes[flextype])
2575                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2576                 if arg != -1:
2577                     argend = find_end_of_inset(document.body, arg)
2578                     if argend == -1:
2579                         document.warning("Can't find end of Argument!")
2580                         i += 1
2581                         continue
2582                     # Find containing paragraph layout
2583                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2584                     endPlain = find_end_of_layout(document.body, beginPlain)
2585                     argcontent = document.body[beginPlain + 1 : endPlain]
2586                     # Adjust range end
2587                     z = z - len(document.body[arg : argend + 1])
2588                     # Remove arg inset
2589                     del document.body[arg : argend + 1]
2590                     pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2591                 arg = find_token(document.body, "\\begin_inset Argument 2", i, z)
2592                 if arg != -1:
2593                     argend = find_end_of_inset(document.body, arg)
2594                     if argend == -1:
2595                         document.warning("Can't find end of Argument!")
2596                         i += 1
2597                         continue
2598                     # Find containing paragraph layout
2599                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2600                     endPlain = find_end_of_layout(document.body, beginPlain)
2601                     argcontent = document.body[beginPlain + 1 : endPlain]
2602                     # Adjust range end
2603                     z = z - len(document.body[arg : argend + 1])
2604                     # Remove arg inset
2605                     del document.body[arg : argend + 1]
2606                     if flextype == "Alternative":
2607                         pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
2608                     else:
2609                         pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2610                 pre += put_cmd_in_ert("{")
2611                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2612                 endPlain = find_end_of_layout(document.body, beginPlain)
2613                 # Adjust range end
2614                 z = z - len(document.body[i : beginPlain + 1])
2615                 z += len(pre)
2616                 document.body[i : beginPlain + 1] = pre
2617                 post = put_cmd_in_ert("}")
2618                 document.body[z - 2 : z + 1] = post
2619             elif flextype in old_flexes:
2620                 pre = put_cmd_in_ert(old_flexes[flextype])
2621                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2622                 if arg == -1:
2623                     i += 1
2624                     continue
2625                 argend = find_end_of_inset(document.body, arg)
2626                 if argend == -1:
2627                     document.warning("Can't find end of Argument!")
2628                     i += 1
2629                     continue
2630                 # Find containing paragraph layout
2631                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2632                 endPlain = find_end_of_layout(document.body, beginPlain)
2633                 argcontent = document.body[beginPlain + 1 : endPlain]
2634                 # Adjust range end
2635                 z = z - len(document.body[arg : argend + 1])
2636                 # Remove arg inset
2637                 del document.body[arg : argend + 1]
2638                 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2639                 pre += put_cmd_in_ert("{")
2640                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2641                 endPlain = find_end_of_layout(document.body, beginPlain)
2642                 # Adjust range end
2643                 z = z - len(document.body[i : beginPlain + 1])
2644                 z += len(pre)
2645                 document.body[i : beginPlain + 1] = pre
2646                 post = put_cmd_in_ert("}")
2647                 document.body[z - 2 : z + 1] = post
2648         
2649         i += 1
2650
2651
2652 def revert_beamerblocks(document):
2653     " Reverts beamer block arguments to ERT "
2654     
2655     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2656     if document.textclass not in beamer_classes:
2657         return
2658
2659     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2660
2661     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2662     i = 0
2663     while True:
2664         i = find_token(document.body, "\\begin_inset Argument", i)
2665         if i == -1:
2666             return
2667         # Find containing paragraph layout
2668         parent = get_containing_layout(document.body, i)
2669         if parent == False:
2670             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2671             i = i + 1
2672             continue
2673         parbeg = parent[1]
2674         parend = parent[2]
2675         realparbeg = parent[3]
2676         layoutname = parent[0]
2677         realparend = parend
2678         for p in range(parbeg, parend):
2679             if p >= realparend:
2680                 i = realparend
2681                 break
2682             if layoutname in blocks:
2683                 m = rx.match(document.body[p])
2684                 if m:
2685                     argnr = m.group(1)
2686                     if argnr == "1":
2687                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2688                         endPlain = find_end_of_layout(document.body, beginPlain)
2689                         endInset = find_end_of_inset(document.body, p)
2690                         content = document.body[beginPlain + 1 : endPlain]
2691                         # Adjust range end
2692                         realparend = realparend - len(document.body[p : endInset + 1])
2693                         # Remove arg inset
2694                         del document.body[p : endInset + 1]
2695                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2696                         document.body[realparbeg : realparbeg] = subst
2697                     elif argnr == "2":
2698                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2699                         endPlain = find_end_of_layout(document.body, beginPlain)
2700                         endInset = find_end_of_inset(document.body, p)
2701                         content = document.body[beginPlain + 1 : endPlain]
2702                         # Adjust range end
2703                         realparend = realparend - len(document.body[p : endInset + 1])
2704                         # Remove arg inset
2705                         del document.body[p : endInset + 1]
2706                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2707                         document.body[realparbeg : realparbeg] = subst
2708         i = realparend
2709
2710
2711
2712 def convert_beamerblocks(document):
2713     " Converts beamer block ERT args to native InsetArgs "
2714     
2715     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2716     if document.textclass not in beamer_classes:
2717         return
2718    
2719     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2720     for lay in blocks:
2721         i = 0
2722         while True:
2723             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2724             if i == -1:
2725                 break
2726             parent = get_containing_layout(document.body, i)
2727             if parent == False or parent[1] != i:
2728                 document.warning("Wrong parent layout!")
2729                 i += 1
2730                 continue
2731             j = parent[2]
2732             parbeg = parent[3]
2733             if i != -1:
2734                 if document.body[parbeg] == "\\begin_inset ERT":
2735                     ertcont = parbeg + 5
2736                     while True:
2737                         if document.body[ertcont].startswith("<"):
2738                             # This is an overlay specification
2739                             # strip off the <
2740                             document.body[ertcont] = document.body[ertcont][1:]
2741                             if document.body[ertcont].endswith(">"):
2742                                 # strip off the >
2743                                 document.body[ertcont] = document.body[ertcont][:-1]
2744                                 # Convert to ArgInset
2745                                 document.body[parbeg] = "\\begin_inset Argument 1"
2746                             elif document.body[ertcont].endswith("}"):
2747                                 # divide the args
2748                                 tok = document.body[ertcont].find('>{')
2749                                 if tok != -1:
2750                                     document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2751                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2752                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
2753                                                                             document.body[ertcont][tok + 2:-1]]
2754                             # Convert to ArgInset
2755                             document.body[parbeg] = "\\begin_inset Argument 1"
2756                         elif document.body[ertcont].startswith("{"):
2757                             # This is the block title
2758                             if document.body[ertcont].endswith("}"):
2759                                 # strip off the braces
2760                                 document.body[ertcont] = document.body[ertcont][1:-1]
2761                                 # Convert to ArgInset
2762                                 document.body[parbeg] = "\\begin_inset Argument 2"
2763                             elif count_pars_in_inset(document.body, ertcont) > 1:
2764                                 # Multipar ERT. Skip this.
2765                                 break
2766                             else:
2767                                 convert_TeX_brace_to_Argument(document, i, 2, 2, False, True)
2768                         else:
2769                             break
2770                         j = find_end_of_layout(document.body, i)
2771                         if j == -1:
2772                             document.warning("end of layout not found!")
2773                         k = find_token(document.body, "\\begin_inset Argument", i, j)
2774                         if k == -1:
2775                             document.warning("InsetArgument not found!")
2776                             break
2777                         l = find_end_of_inset(document.body, k)
2778                         m = find_token(document.body, "\\begin_inset ERT", l, j)
2779                         if m == -1:
2780                             break
2781                         ertcont = m + 5
2782                         parbeg = m
2783             i = j
2784
2785
2786 def convert_overprint(document):
2787     " Convert old beamer overprint layouts to ERT "
2788     
2789     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2790     if document.textclass not in beamer_classes:
2791         return
2792
2793     i = 0
2794     while True:
2795         i = find_token(document.body, "\\begin_layout Overprint", i)
2796         if i == -1:
2797             return
2798         # Find end of sequence
2799         j = find_end_of_sequence(document.body, i)
2800         if j == -1:
2801             document.warning("Malformed lyx document. Cannot find end of Overprint sequence!")
2802             i = i + 1
2803             continue
2804         endseq = j
2805         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
2806         esubst = list()
2807         if document.body[j] == "\\end_deeper":
2808             esubst = ["", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
2809         else:
2810             esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
2811         endseq = endseq + len(esubst) - len(document.body[j : j])
2812         document.body[j : j] = esubst
2813         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
2814         if argbeg != -1:
2815             argend = find_end_of_layout(document.body, argbeg)
2816             if argend == -1:
2817                 document.warning("Malformed lyx document. Cannot find end of Overprint argument!")
2818                 i = i + 1
2819                 continue
2820             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
2821             endPlain = find_end_of_layout(document.body, beginPlain)
2822             content = document.body[beginPlain + 1 : endPlain]
2823             # Adjust range end
2824             endseq = endseq - len(document.body[argbeg : argend + 1])
2825             # Remove arg inset
2826             del document.body[argbeg : argend + 1]
2827             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2828             
2829         endseq = endseq - len(document.body[i : i])
2830         document.body[i : i] = subst + ["\\end_layout"]
2831         endseq += len(subst)
2832         
2833         for p in range(i, endseq):
2834             if document.body[p] == "\\begin_layout Overprint":
2835                 document.body[p] = "\\begin_layout Standard"
2836
2837         i = endseq
2838
2839
2840 def revert_overprint(document):
2841     " Revert old beamer overprint layouts to ERT "
2842     
2843     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2844     if document.textclass not in beamer_classes:
2845         return
2846
2847     i = 0
2848     while True:
2849         i = find_token(document.body, "\\begin_layout Overprint", i)
2850         if i == -1:
2851             return
2852         # Find end of sequence
2853         j = find_end_of_sequence(document.body, i)
2854         if j == -1:
2855             document.warning("Malformed lyx document. Cannot find end of Overprint sequence!")
2856             i = i + 1
2857             continue
2858         endseq = j
2859         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
2860         esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}")
2861         endseq = endseq + len(esubst) - len(document.body[j : j])
2862         if document.body[j] == "\\end_deeper":
2863             document.body[j : j] = ["\\end_deeper", ""] + esubst
2864         else:
2865             document.body[j : j] = esubst
2866         r = i
2867         while r < j:
2868             if document.body[r] == "\\begin_deeper":
2869                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
2870                 if s != -1:
2871                     document.body[r] = ""
2872                     document.body[s] = ""
2873                     r = s
2874                     continue
2875             r = r + 1
2876         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
2877         if argbeg != -1:
2878             argend = find_end_of_inset(document.body, argbeg)
2879             if argend == -1:
2880                 document.warning("Malformed lyx document. Cannot find end of Overprint argument!")
2881                 i = i + 1
2882                 continue
2883             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
2884             endPlain = find_end_of_layout(document.body, beginPlain)
2885             content = document.body[beginPlain + 1 : endPlain]
2886             # Adjust range end
2887             endseq = endseq - len(document.body[argbeg : argend])
2888             # Remove arg inset
2889             del document.body[argbeg : argend + 1]
2890             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2891             
2892         endseq = endseq - len(document.body[i : i])
2893         document.body[i : i] = subst + ["\\end_layout"]
2894         endseq += len(subst)
2895      
2896         p = i
2897         while True:
2898             if p >= endseq:
2899                 break
2900             if document.body[p] == "\\begin_layout Overprint":
2901                 q = find_end_of_layout(document.body, p)
2902                 if q == -1:
2903                     document.warning("Malformed lyx document. Cannot find end of Overprint layout!")
2904                     p += 1
2905                     continue
2906                 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\onslide")
2907                 argbeg = find_token(document.body, "\\begin_inset Argument item:1", p, q)
2908                 if argbeg != -1:
2909                     argend = find_end_of_inset(document.body, argbeg)
2910                     if argend == -1:
2911                         document.warning("Malformed lyx document. Cannot find end of Overprint item argument!")
2912                         p += 1
2913                         continue
2914                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
2915                     endPlain = find_end_of_layout(document.body, beginPlain)
2916                     content = document.body[beginPlain + 1 : endPlain]
2917                     # Adjust range end
2918                     endseq = endseq - len(document.body[argbeg : argend + 1])
2919                     # Remove arg inset
2920                     del document.body[argbeg : argend + 1]
2921                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2922                 endseq = endseq - len(document.body[p : p + 1]) + len(subst)
2923                 document.body[p : p + 1] = subst
2924             p = p + 1
2925
2926         i = endseq
2927
2928
2929 def revert_frametitle(document):
2930     " Reverts beamer frametitle layout to ERT "
2931     
2932     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2933     if document.textclass not in beamer_classes:
2934         return
2935
2936     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2937     i = 0
2938     while True:
2939         i = find_token(document.body, "\\begin_layout FrameTitle", i)
2940         if i == -1:
2941             return
2942         j = find_end_of_layout(document.body, i)
2943         if j == -1:
2944             document.warning("Malformed lyx document: Can't find end of FrameTitle layout")
2945             i = i + 1
2946             continue
2947         endlay = j
2948         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
2949         endlay += len(put_cmd_in_ert("}"))
2950         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\frametitle")
2951         for p in range(i, j):
2952             if p >= endlay:
2953                 break
2954             m = rx.match(document.body[p])
2955             if m:
2956                 argnr = m.group(1)
2957                 if argnr == "1":
2958                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2959                     endPlain = find_end_of_layout(document.body, beginPlain)
2960                     endInset = find_end_of_inset(document.body, p)
2961                     content = document.body[beginPlain + 1 : endPlain]
2962                     # Adjust range end
2963                     endlay = endlay - len(document.body[p : endInset + 1])
2964                     # Remove arg inset
2965                     del document.body[p : endInset + 1]
2966                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2967                 elif argnr == "2":
2968                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2969                     endPlain = find_end_of_layout(document.body, beginPlain)
2970                     endInset = find_end_of_inset(document.body, p)
2971                     content = document.body[beginPlain + 1 : endPlain]
2972                     # Adjust range end
2973                     endlay = endlay - len(document.body[p : endInset + 1])
2974                     # Remove arg inset
2975                     del document.body[p : endInset + 1]
2976                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2977                     
2978         subst += put_cmd_in_ert("{")
2979         document.body[i : i + 1] = subst
2980         i = endlay
2981
2982
2983 def convert_epigraph(document):
2984     " Converts memoir epigraph to new syntax "
2985     
2986     if document.textclass != "memoir":
2987         return
2988
2989     i = 0
2990     while True:
2991         i = find_token(document.body, "\\begin_layout Epigraph", i)
2992         if i == -1:
2993             return
2994         j = find_end_of_layout(document.body, i)
2995         if j == -1:
2996             document.warning("Malformed lyx document: Can't find end of Epigraph layout")
2997             i = i + 1
2998             continue
2999         endlay = j
3000         subst = list()
3001         ert = find_token(document.body, "\\begin_inset ERT", i, j)
3002         if ert != -1:
3003             endInset = find_end_of_inset(document.body, ert)
3004             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", ert)
3005             endPlain = find_end_of_layout(document.body, beginPlain)
3006             ertcont = beginPlain + 2
3007             if document.body[ertcont] == "}{":
3008                 # strip off the <
3009                 # Convert to ArgInset
3010                 endlay = endlay - 2 * len(document.body[j])
3011                 begsubst = ['\\begin_inset Argument post:1', 'status collapsed', '',
3012                             '\\begin_layout Plain Layout']
3013                 endsubst = ['\\end_layout', '', '\\end_inset', '', document.body[j]]
3014                 document.body[j : j + 1] = endsubst
3015                 document.body[endInset + 1 : endInset + 1] = begsubst
3016                 # Adjust range end
3017                 endlay += len(begsubst) + len(endsubst)
3018                 endlay = endlay - len(document.body[ert : endInset + 1])
3019                 del document.body[ert : endInset + 1]
3020                     
3021         i = endlay
3022
3023
3024 def revert_epigraph(document):
3025     " Reverts memoir epigraph argument to ERT "
3026     
3027     if document.textclass != "memoir":
3028         return
3029
3030     i = 0
3031     while True:
3032         i = find_token(document.body, "\\begin_layout Epigraph", i)
3033         if i == -1:
3034             return
3035         j = find_end_of_layout(document.body, i)
3036         if j == -1:
3037             document.warning("Malformed lyx document: Can't find end of Epigraph layout")
3038             i = i + 1
3039             continue
3040         endlay = j
3041         subst = list()
3042         p = find_token(document.body, "\\begin_layout Argument post:1", i, j)
3043         if p != -1:
3044             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3045             endPlain = find_end_of_layout(document.body, beginPlain)
3046             endInset = find_end_of_inset(document.body, p)
3047             content = document.body[beginPlain + 1 : endPlain]
3048             # Adjust range end
3049             endlay = endlay - len(document.body[p : endInset + 1])
3050             # Remove arg inset
3051             del document.body[p : endInset + 1]
3052             subst += put_cmd_in_ert("}{") + content
3053         else:
3054             subst += put_cmd_in_ert("}{")
3055                     
3056         document.body[j : j] = subst + document.body[j : j]
3057         i = endlay
3058
3059
3060 def convert_captioninsets(document):
3061     " Converts caption insets to new syntax "
3062     
3063     i = 0
3064     while True:
3065       i = find_token(document.body, "\\begin_inset Caption", i)
3066       if i == -1:
3067           return
3068       document.body[i] = "\\begin_inset Caption Standard"
3069       i = i + 1
3070         
3071
3072
3073 def revert_captioninsets(document):
3074     " Reverts caption insets to old syntax "
3075     
3076     i = 0
3077     while True:
3078       i = find_token(document.body, "\\begin_inset Caption Standard", i)
3079       if i == -1:
3080           return
3081       document.body[i] = "\\begin_inset Caption"
3082       i = i + 1
3083
3084
3085 def convert_captionlayouts(document):
3086     " Convert caption layouts to caption insets. "
3087     
3088     caption_dict = {
3089         "Captionabove":  "Above",
3090         "Captionbelow":  "Below",
3091         "FigCaption"  :  "FigCaption",
3092         "Table_Caption" :  "Table",
3093         "CenteredCaption" : "Centered",
3094         "Bicaption" : "Bicaption",
3095         }
3096     
3097     i = 0
3098     while True:
3099         i = find_token(document.body, "\\begin_layout", i)
3100         if i == -1:
3101             return
3102         val = get_value(document.body, "\\begin_layout", i)
3103         if val in caption_dict.keys():
3104             j = find_end_of_layout(document.body, i)
3105             if j == -1:
3106                 document.warning("Malformed LyX document: Missing `\\end_layout'.")
3107                 return
3108
3109             document.body[j:j] = ["\\end_layout", "", "\\end_inset", "", ""]
3110             document.body[i:i+1] = ["\\begin_layout %s" % document.default_layout,
3111                                     "\\begin_inset Caption %s" % caption_dict[val], "",
3112                                     "\\begin_layout %s" % document.default_layout]
3113         i = i + 1
3114
3115
3116 def revert_captionlayouts(document):
3117     " Revert caption insets to caption layouts. "
3118     
3119     caption_dict = {
3120         "Above" : "Captionabove",
3121         "Below" : "Captionbelow",
3122         "FigCaption"  :  "FigCaption",
3123         "Table" : "Table_Caption",
3124         "Centered" : "CenteredCaption",
3125         "Bicaption" : "Bicaption",
3126         }
3127     
3128     i = 0
3129     rx = re.compile(r'^\\begin_inset Caption (\S+)$')
3130     while True:
3131         i = find_token(document.body, "\\begin_inset Caption", i)
3132         if i == -1:
3133             return
3134
3135         m = rx.match(document.body[i])
3136         val = ""
3137         if m:
3138             val = m.group(1)
3139         if val not in caption_dict.keys():
3140             i = i + 1
3141             continue
3142         
3143         # We either need to delete the previous \begin_layout line, or we
3144         # need to end the previous layout if this inset is not in the first
3145         # position of the paragraph.
3146         layout_before = find_token_backwards(document.body, "\\begin_layout", i)
3147         if layout_before == -1:
3148             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3149             return
3150         layout_line = document.body[layout_before]
3151         del_layout_before = True
3152         l = layout_before + 1
3153         while l < i:
3154             if document.body[l] != "":
3155                 del_layout_before = False
3156                 break
3157             l = l + 1
3158         if del_layout_before:
3159             del document.body[layout_before:i]
3160             i = layout_before
3161         else:
3162             document.body[i:i] = ["\\end_layout", ""]
3163             i = i + 2
3164
3165         # Find start of layout in the inset and end of inset
3166         j = find_token(document.body, "\\begin_layout", i)
3167         if j == -1:
3168             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3169             return
3170         k = find_end_of_inset(document.body, i)
3171         if k == -1:
3172             document.warning("Malformed LyX document: Missing `\\end_inset'.")
3173             return
3174
3175         # We either need to delete the following \end_layout line, or we need
3176         # to restart the old layout if this inset is not at the paragraph end.
3177         layout_after = find_token(document.body, "\\end_layout", k)
3178         if layout_after == -1:
3179             document.warning("Malformed LyX document: Missing `\\end_layout'.")
3180             return
3181         del_layout_after = True
3182         l = k + 1
3183         while l < layout_after:
3184             if document.body[l] != "":
3185                 del_layout_after = False
3186                 break
3187             l = l + 1
3188         if del_layout_after:
3189             del document.body[k+1:layout_after+1]
3190         else:
3191             document.body[k+1:k+1] = [layout_line, ""]
3192
3193         # delete \begin_layout and \end_inset and replace \begin_inset with
3194         # "\begin_layout XXX". This works because we can only have one
3195         # paragraph in the caption inset: The old \end_layout will be recycled.
3196         del document.body[k]
3197         if document.body[k] == "":
3198             del document.body[k]
3199         del document.body[j]
3200         if document.body[j] == "":
3201             del document.body[j]
3202         document.body[i] = "\\begin_layout %s" % caption_dict[val]
3203         if document.body[i+1] == "":
3204             del document.body[i+1]
3205         i = i + 1
3206
3207
3208 def revert_fragileframe(document):
3209     " Reverts beamer FragileFrame layout to ERT "
3210     
3211     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3212     if document.textclass not in beamer_classes:
3213         return
3214
3215     i = 0
3216     while True:
3217         i = find_token(document.body, "\\begin_layout FragileFrame", i)
3218         if i == -1:
3219             return
3220         # Find end of sequence
3221         j = find_end_of_sequence(document.body, i)
3222         if j == -1:
3223             document.warning("Malformed lyx document. Cannot find end of FragileFrame sequence!")
3224             i = i + 1
3225             continue
3226         endseq = j
3227         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{frame}")
3228         esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{frame}")
3229         endseq = endseq + len(esubst) - len(document.body[j : j])
3230         if document.body[j] == "\\end_deeper":
3231             document.body[j : j] = ["\\end_deeper", ""] + esubst
3232         else:
3233             document.body[j : j] = esubst
3234         for q in range(i, j):
3235             if document.body[q] == "\\begin_layout FragileFrame":
3236                 document.body[q] = "\\begin_layout %s" % document.default_layout
3237         r = i
3238         while r < j:
3239             if document.body[r] == "\\begin_deeper":
3240                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3241                 if s != -1:
3242                     document.body[r] = ""
3243                     document.body[s] = ""
3244                     r = s
3245                     continue
3246             r = r + 1
3247         for p in range(1, 5):
3248             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, j)
3249             if arg != -1:
3250                 if p == 1:
3251                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3252                     endPlain = find_end_of_layout(document.body, beginPlain)
3253                     endInset = find_end_of_inset(document.body, arg)
3254                     content = document.body[beginPlain + 1 : endPlain]
3255                     # Adjust range end
3256                     j = j - len(document.body[arg : endInset + 1])
3257                     # Remove arg inset
3258                     del document.body[arg : endInset + 1]
3259                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3260                 elif p == 2:
3261                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3262                     endPlain = find_end_of_layout(document.body, beginPlain)
3263                     endInset = find_end_of_inset(document.body, arg)
3264                     content = document.body[beginPlain + 1 : endPlain]
3265                     # Adjust range end
3266                     j = j - len(document.body[arg : endInset + 1])
3267                     # Remove arg inset
3268                     del document.body[arg : endInset + 1]
3269                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3270                 elif p == 3:
3271                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3272                     endPlain = find_end_of_layout(document.body, beginPlain)
3273                     endInset = find_end_of_inset(document.body, arg)
3274                     content = document.body[beginPlain + 1 : endPlain]
3275                     # Adjust range end
3276                     j = j - len(document.body[arg : endInset + 1])
3277                     # Remove arg inset
3278                     del document.body[arg : endInset + 1]
3279                     subst += put_cmd_in_ert("[fragile,") + content + put_cmd_in_ert("]")
3280                 elif p == 4:
3281                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3282                     endPlain = find_end_of_layout(document.body, beginPlain)
3283                     endInset = find_end_of_inset(document.body, arg)
3284                     content = document.body[beginPlain + 1 : endPlain]
3285                     # Adjust range end
3286                     j = j - len(document.body[arg : endInset + 1])
3287                     # Remove arg inset
3288                     del document.body[arg : endInset + 1]
3289                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3290             elif p == 3:
3291                 subst += put_cmd_in_ert("[fragile]")
3292                     
3293         document.body[i : i + 1] = subst
3294         i = j
3295
3296
3297 def revert_newframes(document):
3298     " Reverts beamer Frame and PlainFrame layouts to old forms "
3299     
3300     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3301     if document.textclass not in beamer_classes:
3302         return
3303
3304     frame_dict = {
3305         "Frame" : "BeginFrame",
3306         "PlainFrame" : "BeginPlainFrame",
3307         }
3308
3309     rx = re.compile(r'^\\begin_layout (\S+)$')
3310     i = 0
3311     while True:
3312         i = find_token(document.body, "\\begin_layout", i)
3313         if i == -1:
3314             return
3315
3316         m = rx.match(document.body[i])
3317         val = ""
3318         if m:
3319             val = m.group(1)
3320         if val not in frame_dict.keys():
3321             i = i + 1
3322             continue
3323         # Find end of sequence
3324         j = find_end_of_sequence(document.body, i)
3325         if j == -1:
3326             document.warning("Malformed lyx document. Cannot find end of Frame sequence!")
3327             i = i + 1
3328             continue
3329         endseq = j
3330         subst = ["\\begin_layout %s" % frame_dict[val]]
3331         esubst = ["\\end_layout", "", "\\begin_layout EndFrame", "", "\\end_layout"]
3332         endseq = endseq + len(esubst) - len(document.body[j : j])
3333         if document.body[j] == "\\end_deeper":
3334             document.body[j : j] = ["\\end_deeper", ""] + esubst
3335         else:
3336             document.body[j : j] = esubst
3337         for q in range(i, j):
3338             if document.body[q] == "\\begin_layout %s" % val:
3339                 document.body[q] = "\\begin_layout %s" % document.default_layout
3340         r = i
3341         while r < j:
3342             if document.body[r] == "\\begin_deeper":
3343                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3344                 if s != -1:
3345                     document.body[r] = ""
3346                     document.body[s] = ""
3347                     r = s
3348                     continue
3349             r = r + 1
3350         l = find_end_of_layout(document.body, i)
3351         for p in range(1, 5):
3352             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, l)
3353             if arg != -1:
3354                 if p == 1:
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                     l = l - 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 == 2:
3365                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3366                     endPlain = find_end_of_layout(document.body, beginPlain)
3367                     endInset = find_end_of_inset(document.body, arg)
3368                     content = document.body[beginPlain + 1 : endPlain]
3369                     # Adjust range end
3370                     l = l - len(document.body[arg : endInset + 1])
3371                     # Remove arg inset
3372                     del document.body[arg : endInset + 1]
3373                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3374                 elif p == 3:
3375                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3376                     endPlain = find_end_of_layout(document.body, beginPlain)
3377                     endInset = find_end_of_inset(document.body, arg)
3378                     content = document.body[beginPlain + 1 : endPlain]
3379                     # Adjust range end
3380                     l = l - len(document.body[arg : endInset + 1])
3381                     # Remove arg inset
3382                     del document.body[arg : endInset + 1]
3383                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3384                 elif p == 4:
3385                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3386                     endPlain = find_end_of_layout(document.body, beginPlain)
3387                     endInset = find_end_of_inset(document.body, arg)
3388                     content = document.body[beginPlain + 1 : endPlain]
3389                     # Adjust range end
3390                     l = l - len(document.body[arg : endInset + 1])
3391                     # Remove arg inset
3392                     del document.body[arg : endInset + 1]
3393                     subst += content
3394                     
3395         document.body[i : i + 1] = subst
3396         i = j
3397
3398
3399 ##
3400 # Conversion hub
3401 #
3402
3403 supported_versions = ["2.1.0","2.1"]
3404 convert = [
3405            [414, []],
3406            [415, [convert_undertilde]],
3407            [416, []],
3408            [417, [convert_japanese_encodings]],
3409            [418, []],
3410            [419, []],
3411            [420, [convert_biblio_style]],
3412            [421, [convert_longtable_captions]],
3413            [422, [convert_use_packages]],
3414            [423, [convert_use_mathtools]],
3415            [424, [convert_cite_engine_type]],
3416            [425, []],
3417            [426, []],
3418            [427, []],
3419            [428, [convert_cell_rotation]],
3420            [429, [convert_table_rotation]],
3421            [430, [convert_listoflistings]],
3422            [431, [convert_use_amssymb]],
3423            [432, []],
3424            [433, [convert_armenian]],
3425            [434, []],
3426            [435, []],
3427            [436, []],
3428            [437, []],
3429            [438, []],
3430            [439, []],
3431            [440, []],
3432            [441, [convert_mdnomath]],
3433            [442, []],
3434            [443, []],
3435            [444, []],
3436            [445, []],
3437            [446, [convert_latexargs]],
3438            [447, [convert_IEEEtran, convert_AASTeX, convert_AGUTeX, convert_IJMP, convert_SIGPLAN, convert_SIGGRAPH, convert_EuropeCV, convert_Initials]],
3439            [448, [convert_literate]],
3440            [449, []],
3441            [450, []],
3442            [451, [convert_beamerargs, convert_againframe_args, convert_corollary_args, convert_quote_args]],
3443            [452, [convert_beamerblocks]],
3444            [453, [convert_use_stmaryrd]],
3445            [454, [convert_overprint]],
3446            [455, []],
3447            [456, [convert_epigraph]],
3448            [457, [convert_use_stackrel]],
3449            [458, [convert_captioninsets, convert_captionlayouts]],
3450            [459, []]
3451           ]
3452
3453 revert =  [
3454            [458, [revert_fragileframe, revert_newframes]],
3455            [457, [revert_captioninsets, revert_captionlayouts]],
3456            [456, [revert_use_stackrel]],
3457            [455, [revert_epigraph]],
3458            [454, [revert_frametitle]],
3459            [453, [revert_overprint]],
3460            [452, [revert_use_stmaryrd]],
3461            [451, [revert_beamerblocks]],
3462            [450, [revert_beamerargs, revert_beamerargs2, revert_beamerargs3, revert_beamerflex]],
3463            [449, [revert_garamondx, revert_garamondx_newtxmath]],
3464            [448, [revert_itemargs]],
3465            [447, [revert_literate]],
3466            [446, [revert_IEEEtran, revert_AASTeX, revert_AGUTeX, revert_IJMP, revert_SIGPLAN, revert_SIGGRAPH, revert_EuropeCV, revert_Initials]],
3467            [445, [revert_latexargs]],
3468            [444, [revert_uop]],
3469            [443, [revert_biolinum]],
3470            [442, []],
3471            [441, [revert_newtxmath]],
3472            [440, [revert_mdnomath]],
3473            [439, [revert_mathfonts]],
3474            [438, [revert_minionpro]],
3475            [437, [revert_ipadeco, revert_ipachar]],
3476            [436, [revert_texgyre]],
3477            [435, [revert_mathdesign]],
3478            [434, [revert_txtt]],
3479            [433, [revert_libertine]],
3480            [432, [revert_armenian]],
3481            [431, [revert_languages, revert_ancientgreek]],
3482            [430, [revert_use_amssymb]],
3483            [429, [revert_listoflistings]],
3484            [428, [revert_table_rotation]],
3485            [427, [revert_cell_rotation]],
3486            [426, [revert_tipa]],
3487            [425, [revert_verbatim]],
3488            [424, [revert_cancel]],
3489            [423, [revert_cite_engine_type]],
3490            [422, [revert_use_mathtools]],
3491            [421, [revert_use_packages]],
3492            [420, [revert_longtable_captions]],
3493            [419, [revert_biblio_style]],
3494            [418, [revert_australian]],
3495            [417, [revert_justification]],
3496            [416, [revert_japanese_encodings]],
3497            [415, [revert_negative_space, revert_math_spaces]],
3498            [414, [revert_undertilde]],
3499            [413, [revert_visible_space]]
3500           ]
3501
3502
3503 if __name__ == "__main__":
3504     pass