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