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