]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_1.py
4c56ae05afc8af032bb463af26e2bda327b843d7
[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 del_token, find_token, find_token_exact, find_token_backwards, find_end_of, \
29     find_end_of_inset, find_end_of_layout, find_re, get_option_value, get_containing_layout, \
30     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_cite_engine_type(document):
421     "Determine the \\cite_engine_type from the citation engine."
422     i = find_token(document.header, "\\cite_engine", 0)
423     if i == -1:
424         return
425     engine = get_value(document.header, "\\cite_engine", i)
426     if "_" in engine:
427         engine, type = engine.split("_")
428     else:
429         type = {"basic": "numerical", "jurabib": "authoryear"}[engine]
430     document.header[i] = "\\cite_engine " + engine
431     document.header.insert(i + 1, "\\cite_engine_type " + type)
432
433
434 def revert_cite_engine_type(document):
435     "Natbib had the type appended with an underscore."
436     engine_type = "numerical"
437     i = find_token(document.header, "\\cite_engine_type" , 0)
438     if i == -1:
439         document.warning("No \\cite_engine_type line. Assuming numerical.")
440     else:
441         engine_type = get_value(document.header, "\\cite_engine_type", i)
442         del document.header[i]
443
444     # We are looking for the natbib citation engine
445     i = find_token(document.header, "\\cite_engine natbib", 0)
446     if i == -1:
447         return
448     document.header[i] = "\\cite_engine natbib_" + engine_type
449
450
451 def revert_cancel(document):
452     "add cancel to the preamble if necessary"
453     commands = ["cancelto", "cancel", "bcancel", "xcancel"]
454     i = 0
455     while True:
456         i = find_token(document.body, '\\begin_inset Formula', i)
457         if i == -1:
458             return
459         j = find_end_of_inset(document.body, i)
460         if j == -1:
461             document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
462             i += 1
463             continue
464         code = "\n".join(document.body[i:j])
465         for c in commands:
466             if code.find("\\%s" % c) != -1:
467                 add_to_preamble(document, ["\\usepackage{cancel}"])
468                 return
469         i = j
470
471
472 def revert_verbatim(document):
473     " Revert verbatim einvironments completely to TeX-code. "
474     i = 0
475     consecutive = False
476     subst_end = ['\end_layout', '', '\\begin_layout Plain Layout',
477                  '\end_layout', '',
478                  '\\begin_layout Plain Layout', '', '',
479                  '\\backslash', '',
480                  'end{verbatim}',
481                  '\\end_layout', '', '\\end_inset',
482                  '', '', '\\end_layout']
483     subst_begin = ['\\begin_layout Standard', '\\noindent',
484                    '\\begin_inset ERT', 'status collapsed', '',
485                    '\\begin_layout Plain Layout', '', '', '\\backslash',
486                    'begin{verbatim}',
487                    '\\end_layout', '', '\\begin_layout Plain Layout', '']
488     while 1:
489         i = find_token(document.body, "\\begin_layout Verbatim", i)
490         if i == -1:
491             return
492         j = find_end_of_layout(document.body, i)
493         if j == -1:
494             document.warning("Malformed lyx document: Can't find end of Verbatim layout")
495             i += 1
496             continue
497         # delete all line breaks insets (there are no other insets)
498         l = i
499         while 1:
500             n = find_token(document.body, "\\begin_inset Newline newline", l)
501             if n == -1:
502                 n = find_token(document.body, "\\begin_inset Newline linebreak", l)
503                 if n == -1:
504                     break
505             m = find_end_of_inset(document.body, n)
506             del(document.body[m:m+1])
507             document.body[n:n+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
508             l += 1
509             j += 1
510         # consecutive verbatim environments need to be connected
511         k = find_token(document.body, "\\begin_layout Verbatim", j)
512         if k == j + 2 and consecutive == False:
513             consecutive = True
514             document.body[j:j+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
515             document.body[i:i+1] = subst_begin
516             continue
517         if k == j + 2 and consecutive == True:
518             document.body[j:j+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
519             del(document.body[i:i+1])
520             continue
521         if k != j + 2 and consecutive == True:
522             document.body[j:j+1] = subst_end
523             # the next paragraph must not be indented
524             document.body[j+19:j+19] = ['\\noindent']
525             del(document.body[i:i+1])
526             consecutive = False
527             continue
528         else:
529             document.body[j:j+1] = subst_end
530             # the next paragraph must not be indented
531             document.body[j+19:j+19] = ['\\noindent']
532             document.body[i:i+1] = subst_begin
533
534
535 def revert_tipa(document):
536     " Revert native TIPA insets to mathed or ERT. "
537     i = 0
538     while 1:
539         i = find_token(document.body, "\\begin_inset IPA", i)
540         if i == -1:
541             return
542         j = find_end_of_inset(document.body, i)
543         if j == -1:
544             document.warning("Malformed lyx document: Can't find end of IPA inset")
545             i += 1
546             continue
547         Multipar = False
548         n = find_token(document.body, "\\begin_layout", i, j)
549         if n == -1:
550             document.warning("Malformed lyx document: IPA inset has no embedded layout")
551             i += 1
552             continue
553         m = find_end_of_layout(document.body, n)
554         if m == -1:
555             document.warning("Malformed lyx document: Can't find end of embedded layout")
556             i += 1
557             continue
558         content = document.body[n+1:m]
559         p = find_token(document.body, "\\begin_layout", m, j)
560         if p != -1 or len(content) > 1:
561             Multipar = True
562             content = document.body[i+1:j]
563         if Multipar:
564             # IPA insets with multiple pars need to be wrapped by \begin{IPA}...\end{IPA}
565             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}")
566             add_to_preamble(document, ["\\usepackage{tipa,tipx}"])
567         else:
568             # single-par IPA insets can be reverted to mathed
569             document.body[i:j+1] = ["\\begin_inset Formula $\\text{\\textipa{" + content[0] + "}}$", "\\end_inset"]
570         i = j
571
572
573 def revert_cell_rotation(document):
574   "Revert cell rotations to TeX-code"
575
576   load_rotating = False
577   i = 0
578   try:
579     while True:
580       # first, let's find out if we need to do anything
581       i = find_token(document.body, '<cell ', i)
582       if i == -1:
583         return
584       j = document.body[i].find('rotate="')
585       if j != -1:
586         k = document.body[i].find('"', j + 8)
587         value = document.body[i][j + 8 : k]
588         if value == "0":
589           rgx = re.compile(r' rotate="[^"]+?"')
590           # remove rotate option
591           document.body[i] = rgx.sub('', document.body[i])
592         elif value == "90":
593           rgx = re.compile(r' rotate="[^"]+?"')
594           document.body[i] = rgx.sub('rotate="true"', document.body[i])
595         else:
596           rgx = re.compile(r' rotate="[^"]+?"')
597           load_rotating = True
598           # remove rotate option
599           document.body[i] = rgx.sub('', document.body[i])
600           # write ERT
601           document.body[i + 5 : i + 5] = \
602             put_cmd_in_ert("\\end{turn}")
603           document.body[i + 4 : i + 4] = \
604             put_cmd_in_ert("\\begin{turn}{" + value + "}")
605         
606       i += 1
607         
608   finally:
609     if load_rotating:
610       add_to_preamble(document, ["\\@ifundefined{turnbox}{\usepackage{rotating}}{}"])
611
612
613 def convert_cell_rotation(document):
614     'Convert cell rotation statements from "true" to "90"'
615
616     i = 0
617     while True:
618       # first, let's find out if we need to do anything
619       i = find_token(document.body, '<cell ', i)
620       if i == -1:
621         return
622       j = document.body[i].find('rotate="true"')
623       if j != -1:
624         rgx = re.compile(r'rotate="[^"]+?"')
625         # convert "true" to "90"
626         document.body[i] = rgx.sub('rotate="90"', document.body[i])
627         
628       i += 1
629
630
631 def revert_table_rotation(document):
632   "Revert table rotations to TeX-code"
633
634   load_rotating = False
635   i = 0
636   try:
637     while True:
638       # first, let's find out if we need to do anything
639       i = find_token(document.body, '<features ', i)
640       if i == -1:
641         return
642       j = document.body[i].find('rotate="')
643       if j != -1:
644         end_table = find_token(document.body, '</lyxtabular>', j)
645         k = document.body[i].find('"', j + 8)
646         value = document.body[i][j + 8 : k]
647         if value == "0":
648           rgx = re.compile(r' rotate="[^"]+?"')
649           # remove rotate option
650           document.body[i] = rgx.sub('', document.body[i])
651         elif value == "90":
652           rgx = re.compile(r'rotate="[^"]+?"')
653           document.body[i] = rgx.sub('rotate="true"', document.body[i])
654         else:
655           rgx = re.compile(r' rotate="[^"]+?"')
656           load_rotating = True
657           # remove rotate option
658           document.body[i] = rgx.sub('', document.body[i])
659           # write ERT
660           document.body[end_table + 3 : end_table + 3] = \
661             put_cmd_in_ert("\\end{turn}")
662           document.body[i - 2 : i - 2] = \
663             put_cmd_in_ert("\\begin{turn}{" + value + "}")
664         
665       i += 1
666         
667   finally:
668     if load_rotating:
669       add_to_preamble(document, ["\\@ifundefined{turnbox}{\usepackage{rotating}}{}"])
670
671
672 def convert_table_rotation(document):
673     'Convert table rotation statements from "true" to "90"'
674
675     i = 0
676     while True:
677       # first, let's find out if we need to do anything
678       i = find_token(document.body, '<features ', i)
679       if i == -1:
680         return
681       j = document.body[i].find('rotate="true"')
682       if j != -1:
683         rgx = re.compile(r'rotate="[^"]+?"')
684         # convert "true" to "90"
685         document.body[i] = rgx.sub('rotate="90"', document.body[i])
686         
687       i += 1
688
689
690 def convert_listoflistings(document):
691     'Convert ERT \lstlistoflistings to TOC lstlistoflistings inset'
692     # We can support roundtrip because the command is so simple
693     i = 0
694     while True:
695         i = find_token(document.body, "\\begin_inset ERT", i)
696         if i == -1:
697             return
698         j = find_end_of_inset(document.body, i)
699         if j == -1:
700             document.warning("Malformed lyx document: Can't find end of ERT inset")
701             i += 1
702             continue
703         ert = get_ert(document.body, i)
704         if ert == "\\lstlistoflistings{}":
705             document.body[i:j] = ["\\begin_inset CommandInset toc", "LatexCommand lstlistoflistings", ""]
706             i = i + 4
707         else:
708             i = j + 1
709
710
711 def revert_listoflistings(document):
712     'Convert TOC lstlistoflistings inset to ERT lstlistoflistings'
713     i = 0
714     while True:
715         i = find_token(document.body, "\\begin_inset CommandInset toc", i)
716         if i == -1:
717             return
718         if document.body[i+1] == "LatexCommand lstlistoflistings":
719             j = find_end_of_inset(document.body, i)
720             if j == -1:
721                 document.warning("Malformed lyx document: Can't find end of TOC inset")
722                 i += 1
723                 continue
724             subst = put_cmd_in_ert("\\lstlistoflistings{}")
725             document.body[i:j+1] = subst
726             add_to_preamble(document, ["\\usepackage{listings}"])
727         i = i + 1
728
729
730 def convert_use_amssymb(document):
731     "insert use_package amssymb"
732     regexp = re.compile(r'(\\use_package\s+amsmath)')
733     i = find_re(document.header, regexp, 0)
734     if i == -1:
735         document.warning("Malformed LyX document: Can't find \\use_package amsmath.")
736         return;
737     value = get_value(document.header, "\\use_package" , i).split()[1]
738     useamsmath = 0
739     try:
740         useamsmath = int(value)
741     except:
742         document.warning("Invalid \\use_package amsmath: " + value + ". Assuming auto.")
743         useamsmath = 1
744     j = find_token(document.preamble, "\\usepackage{amssymb}", 0)
745     if j == -1:
746         document.header.insert(i + 1, "\\use_package amssymb %d" % useamsmath)
747     else:
748         document.header.insert(i + 1, "\\use_package amssymb 2")
749         del document.preamble[j]
750
751
752 def revert_use_amssymb(document):
753     "remove use_package amssymb"
754     regexp1 = re.compile(r'(\\use_package\s+amsmath)')
755     regexp2 = re.compile(r'(\\use_package\s+amssymb)')
756     i = find_re(document.header, regexp1, 0)
757     j = find_re(document.header, regexp2, 0)
758     value1 = "1" # default is auto
759     value2 = "1" # default is auto
760     if i != -1:
761         value1 = get_value(document.header, "\\use_package" , i).split()[1]
762     if j != -1:
763         value2 = get_value(document.header, "\\use_package" , j).split()[1]
764         del document.header[j]
765     if value1 != value2 and value2 == "2": # on
766         add_to_preamble(document, ["\\usepackage{amssymb}"])
767
768
769 def revert_ancientgreek(document):
770     "Set the document language for ancientgreek to greek" 
771
772     if document.language == "ancientgreek": 
773         document.language = "greek"
774         i = find_token(document.header, "\\language", 0) 
775         if i != -1: 
776             document.header[i] = "\\language greek" 
777     j = 0 
778     while True: 
779         j = find_token(document.body, "\\lang ancientgreek", j) 
780         if j == -1:
781             return
782         else:
783             document.body[j] = document.body[j].replace("\\lang ancientgreek", "\\lang greek") 
784         j += 1
785
786
787 def revert_languages(document):
788     "Set the document language for new supported languages to English" 
789
790     languages = [
791                  "coptic", "divehi", "hindi", "kurmanji", "lao", "marathi", "occitan", "sanskrit",
792                  "syriac", "tamil", "telugu", "urdu"
793                 ]
794     for n in range(len(languages)):
795         if document.language == languages[n]:
796             document.language = "english"
797             i = find_token(document.header, "\\language", 0) 
798             if i != -1: 
799                 document.header[i] = "\\language english" 
800         j = 0
801         while j < len(document.body): 
802             j = find_token(document.body, "\\lang " + languages[n], j)
803             if j != -1:
804                 document.body[j] = document.body[j].replace("\\lang " + languages[n], "\\lang english")
805                 j += 1
806             else:
807                 j = len(document.body)
808
809
810 def convert_armenian(document):
811     "Use polyglossia and thus non-TeX fonts for Armenian" 
812
813     if document.language == "armenian": 
814         i = find_token(document.header, "\\use_non_tex_fonts", 0) 
815         if i != -1: 
816             document.header[i] = "\\use_non_tex_fonts true" 
817
818
819 def revert_armenian(document):
820     "Use ArmTeX and thus TeX fonts for Armenian" 
821
822     if document.language == "armenian": 
823         i = find_token(document.header, "\\use_non_tex_fonts", 0) 
824         if i != -1: 
825             document.header[i] = "\\use_non_tex_fonts false" 
826
827
828 def revert_libertine(document):
829     " Revert native libertine font definition to LaTeX " 
830
831     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
832         i = find_token(document.header, "\\font_roman libertine", 0)
833         if i != -1:
834             osf = False
835             j = find_token(document.header, "\\font_osf true", 0)
836             if j != -1:
837                 osf = True
838             preamble = "\\usepackage"
839             if osf:
840                 document.header[j] = "\\font_osf false"
841             else:
842                 preamble += "[lining]"
843             preamble += "{libertine-type1}"
844             add_to_preamble(document, [preamble])
845             document.header[i] = "\\font_roman default"
846
847
848 def revert_txtt(document):
849     " Revert native txtt font definition to LaTeX " 
850
851     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
852         i = find_token(document.header, "\\font_typewriter txtt", 0)
853         if i != -1:
854             preamble = "\\renewcommand{\\ttdefault}{txtt}"
855             add_to_preamble(document, [preamble])
856             document.header[i] = "\\font_typewriter default"
857
858
859 def revert_mathdesign(document):
860     " Revert native mathdesign font definition to LaTeX " 
861
862     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
863         mathdesign_dict = {
864         "mdbch":  "charter",
865         "mdput":  "utopia",
866         "mdugm":  "garamond"
867         }
868         i = find_token(document.header, "\\font_roman", 0)
869         if i == -1:
870             return
871         val = get_value(document.header, "\\font_roman", i)
872         if val in mathdesign_dict.keys():
873             preamble = "\\usepackage[%s" % mathdesign_dict[val]
874             expert = False
875             j = find_token(document.header, "\\font_osf true", 0)
876             if j != -1:
877                 expert = True
878                 document.header[j] = "\\font_osf false"
879             l = find_token(document.header, "\\font_sc true", 0)
880             if l != -1:
881                 expert = True
882                 document.header[l] = "\\font_sc false"
883             if expert:
884                 preamble += ",expert"
885             preamble += "]{mathdesign}"
886             add_to_preamble(document, [preamble])
887             document.header[i] = "\\font_roman default"
888
889
890 def revert_texgyre(document):
891     " Revert native TeXGyre font definition to LaTeX " 
892
893     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
894         texgyre_fonts = ["tgadventor", "tgbonum", "tgchorus", "tgcursor", \
895                          "tgheros", "tgpagella", "tgschola", "tgtermes"]
896         i = find_token(document.header, "\\font_roman", 0)
897         if i != -1:
898             val = get_value(document.header, "\\font_roman", i)
899             if val in texgyre_fonts:
900                 preamble = "\\usepackage{%s}" % val
901                 add_to_preamble(document, [preamble])
902                 document.header[i] = "\\font_roman default"
903         i = find_token(document.header, "\\font_sans", 0)
904         if i != -1:
905             val = get_value(document.header, "\\font_sans", i)
906             if val in texgyre_fonts:
907                 preamble = "\\usepackage{%s}" % val
908                 add_to_preamble(document, [preamble])
909                 document.header[i] = "\\font_sans default"
910         i = find_token(document.header, "\\font_typewriter", 0)
911         if i != -1:
912             val = get_value(document.header, "\\font_typewriter", i)
913             if val in texgyre_fonts:
914                 preamble = "\\usepackage{%s}" % val
915                 add_to_preamble(document, [preamble])
916                 document.header[i] = "\\font_typewriter default"
917
918
919 def revert_ipadeco(document):
920     " Revert IPA decorations to ERT "
921     i = 0
922     while True:
923       i = find_token(document.body, "\\begin_inset IPADeco", i)
924       if i == -1:
925           return
926       end = find_end_of_inset(document.body, i)
927       if end == -1:
928           document.warning("Can't find end of inset at line " + str(i))
929           i += 1
930           continue
931       line = document.body[i]
932       rx = re.compile(r'\\begin_inset IPADeco (.*)$')
933       m = rx.match(line)
934       decotype = m.group(1)
935       if decotype != "toptiebar" and decotype != "bottomtiebar":
936           document.warning("Invalid IPADeco type: " + decotype)
937           i = end
938           continue
939       blay = find_token(document.body, "\\begin_layout Plain Layout", i, end)
940       if blay == -1:
941           document.warning("Can't find layout for inset at line " + str(i))
942           i = end
943           continue
944       bend = find_end_of_layout(document.body, blay)
945       if bend == -1:
946           document.warning("Malformed LyX document: Could not find end of IPADeco inset's layout.")
947           i = end
948           continue
949       substi = ["\\begin_inset ERT", "status collapsed", "",
950                 "\\begin_layout Plain Layout", "", "", "\\backslash", 
951                 decotype + "{", "\\end_layout", "", "\\end_inset"]
952       substj = ["\\size default", "", "\\begin_inset ERT", "status collapsed", "",
953                 "\\begin_layout Plain Layout", "", "}", "\\end_layout", "", "\\end_inset"]
954       # do the later one first so as not to mess up the numbering
955       document.body[bend:end + 1] = substj
956       document.body[i:blay + 1] = substi
957       i = end + len(substi) + len(substj) - (end - bend) - (blay - i) - 2
958       add_to_preamble(document, "\\usepackage{tipa}")
959
960
961 def revert_ipachar(document):
962     ' Revert \\IPAChar to ERT '
963     i = 0
964     found = False
965     while i < len(document.body):
966         m = re.match(r'(.*)\\IPAChar \\(\w+\{\w+\})(.*)', document.body[i])
967         if m:
968             found = True
969             before = m.group(1)
970             ipachar = m.group(2)
971             after = m.group(3)
972             subst = [before,
973                      '\\begin_inset ERT',
974                      'status collapsed', '',
975                      '\\begin_layout Standard',
976                      '', '', '\\backslash',
977                      ipachar,
978                      '\\end_layout', '',
979                      '\\end_inset', '',
980                      after]
981             document.body[i: i+1] = subst
982             i = i + len(subst)
983         else:
984             i = i + 1
985     if found:
986         add_to_preamble(document, "\\usepackage{tone}")
987
988
989 def revert_minionpro(document):
990     " Revert native MinionPro font definition to LaTeX " 
991
992     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
993         i = find_token(document.header, "\\font_roman minionpro", 0)
994         if i != -1:
995             osf = False
996             j = find_token(document.header, "\\font_osf true", 0)
997             if j != -1:
998                 osf = True
999             preamble = "\\usepackage"
1000             if osf:
1001                 document.header[j] = "\\font_osf false"
1002             else:
1003                 preamble += "[lf]"
1004             preamble += "{MinionPro}"
1005             add_to_preamble(document, [preamble])
1006             document.header[i] = "\\font_roman default"
1007
1008
1009 def revert_mathfonts(document):
1010     " Revert native math font definitions to LaTeX " 
1011
1012     i = find_token(document.header, "\\font_math", 0)
1013     if i == -1:
1014        return
1015     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1016         val = get_value(document.header, "\\font_math", i)
1017         if val == "eulervm":
1018             add_to_preamble(document, "\\usepackage{eulervm}")
1019         elif val == "default":
1020             mathfont_dict = {
1021             "lmodern":  "\\renewcommand{\\rmdefault}{lmr}",
1022             "minionpro":  "\\usepackage[onlytext,lf]{MinionPro}",
1023             "minionpro-osf":  "\\usepackage[onlytext]{MinionPro}",
1024             "palatino":  "\\renewcommand{\\rmdefault}{ppl}",
1025             "palatino-osf":  "\\renewcommand{\\rmdefault}{pplj}",
1026             "times":  "\\renewcommand{\\rmdefault}{ptm}",
1027             "utopia":  "\\renewcommand{\\rmdefault}{futs}",
1028             "utopia-osf":  "\\renewcommand{\\rmdefault}{futj}",
1029             }
1030             j = find_token(document.header, "\\font_roman", 0)
1031             if j != -1:
1032                 rm = get_value(document.header, "\\font_roman", j)
1033                 k = find_token(document.header, "\\font_osf true", 0)
1034                 if k != -1:
1035                     rm += "-osf"
1036                 if rm in mathfont_dict.keys():
1037                     add_to_preamble(document, mathfont_dict[rm])
1038                     document.header[j] = "\\font_roman default"
1039                     if k != -1:
1040                         document.header[k] = "\\font_osf false"
1041     del document.header[i]
1042
1043
1044 def revert_mdnomath(document):
1045     " Revert mathdesign and fourier without math " 
1046
1047     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1048         mathdesign_dict = {
1049         "md-charter": "mdbch",
1050         "md-utopia": "mdput",
1051         "md-garamond": "mdugm"
1052         }
1053         i = find_token(document.header, "\\font_roman", 0)
1054         if i == -1:
1055             return
1056         val = get_value(document.header, "\\font_roman", i)
1057         if val in mathdesign_dict.keys():
1058             j = find_token(document.header, "\\font_math", 0)
1059             if j == -1:
1060                 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1061             mval = get_value(document.header, "\\font_math", j)
1062             if mval == "default":
1063                 document.header[i] = "\\font_roman default"
1064                 add_to_preamble(document, "\\renewcommand{\\rmdefault}{%s}" % mathdesign_dict[val])
1065             else:
1066                 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1067
1068
1069 def convert_mdnomath(document):
1070     " Change mathdesign font name " 
1071
1072     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1073         mathdesign_dict = {
1074         "mdbch":  "md-charter",
1075         "mdput":  "md-utopia",
1076         "mdugm":  "md-garamond"
1077         }
1078         i = find_token(document.header, "\\font_roman", 0)
1079         if i == -1:
1080             return
1081         val = get_value(document.header, "\\font_roman", i)
1082         if val in mathdesign_dict.keys():
1083              document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1084
1085
1086 def revert_newtxmath(document):
1087     " Revert native newtxmath 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         mathfont_dict = {
1095         "libertine-ntxm":  "\\usepackage[libertine]{newtxmath}",
1096         "minion-ntxm":  "\\usepackage[minion]{newtxmath}",
1097         "newtxmath":  "\\usepackage{newtxmath}",
1098         }
1099         if val in mathfont_dict.keys():
1100             add_to_preamble(document, mathfont_dict[val])
1101             document.header[i] = "\\font_math auto"
1102
1103
1104 def revert_biolinum(document):
1105     " Revert native biolinum font definition to LaTeX " 
1106
1107     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1108         i = find_token(document.header, "\\font_sans biolinum", 0)
1109         if i != -1:
1110             osf = False
1111             j = find_token(document.header, "\\font_osf true", 0)
1112             if j != -1:
1113                 osf = True
1114             preamble = "\\usepackage"
1115             if not osf:
1116                 preamble += "[lf]"
1117             preamble += "{biolinum-type1}"
1118             add_to_preamble(document, [preamble])
1119             document.header[i] = "\\font_sans default"
1120
1121
1122 def revert_uop(document):
1123     " Revert native URW Classico (Optima) font definition to LaTeX "
1124
1125     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1126         i = find_token(document.header, "\\font_sans uop", 0)
1127         if i != -1:
1128                 preamble = "\\renewcommand{\\sfdefault}{uop}"
1129                 add_to_preamble(document, [preamble])
1130                 document.header[i] = "\\font_sans default"
1131
1132
1133 def convert_latexargs(document):
1134     " Convert InsetArgument to new syntax "
1135
1136     if find_token(document.body, "\\begin_inset Argument", 0) == -1:
1137         # nothing to do.
1138         return
1139
1140     # A list of layouts (document classes) with only optional or no arguments.
1141     # These can be safely converted to the new syntax
1142     # (I took the liberty to add some of my personal layouts/modules here; JSP)
1143     safe_layouts = ["aa", "aapaper", "aastex", "achemso", "acmsiggraph", "AEA",
1144                     "agu-dtd", "agums", "agutex", "amsart", "amsbook", "apa",
1145                     "arab-article", "armenian-article", "article-beamer", "article",
1146                     "beamer", "book", "broadway", "chess", "cl2emult", "ctex-article",
1147                     "ctex-book", "ctex-report", "dinbrief", "docbook-book", "docbook-chapter",
1148                     "docbook", "docbook-section", "doublecol-new", "dtk", "ectaart", "egs",
1149                     "elsarticle", "elsart", "entcs", "europecv", "extarticle", "extbook",
1150                     "extletter", "extreport", "foils", "frletter", "g-brief2", "g-brief",
1151                     "heb-article", "heb-letter", "hollywood", "IEEEtran", "ijmpc", "ijmpd",
1152                     "iopart", "isprs", "jarticle", "jasatex", "jbook", "jgrga", "jreport",
1153                     "jsarticle", "jsbeamer", "jsbook", "jss", "kluwer", "latex8", "letter", "lettre",
1154                     "literate-article", "literate-book", "literate-report", "llncs", "ltugboat",
1155                     "memoir", "moderncv", "mwart", "mwbk", "mwrep", "paper", "powerdot",
1156                     "recipebook", "report", "revtex4", "revtex", "scrartcl", "scrarticle-beamer",
1157                     "scrbook", "scrlettr", "scrlttr2", "scrreprt", "seminar", "siamltex",
1158                     "sigplanconf", "simplecv", "singlecol", "singlecol-new", "slides", "spie",
1159                     "svglobal3", "svglobal", "svjog", "svmono", "svmult", "svprobth", "tarticle",
1160                     "tbook", "treport", "tufte-book", "tufte-handout"]
1161     # A list of "safe" modules, same as above
1162     safe_modules = ["biblatex", "beameraddons", "beamersession", "braille", "customHeadersFooters",
1163                     "endnotes", "enumitem", "eqs-within-sections", "figs-within-sections", "fix-cm",
1164                     "fixltx2e", "foottoend", "hanging", "jscharstyles", "knitr", "lilypond",
1165                     "linguistics", "linguisticx", "logicalmkup", "minimalistic", "nomindex", "noweb",
1166                     "pdfcomment", "sweave", "tabs-within-sections", "theorems-ams-bytype",
1167                     "theorems-ams-extended-bytype", "theorems-ams-extended", "theorems-ams", "theorems-bytype",
1168                     "theorems-chap-bytype", "theorems-chap", "theorems-named", "theorems-sec-bytype",
1169                     "theorems-sec", "theorems-starred", "theorems-std", "todonotes"]
1170     # Modules we need to take care of
1171     caveat_modules = ["initials"]
1172     # information about the relevant styles in caveat_modules (number of opt and req args)
1173     # use this if we get more caveat_modules. For now, use hard coding (see below).
1174     # initials = [{'Layout' : 'Initial', 'opt' : 1, 'req' : 1}]
1175
1176     # Is this a known safe layout?
1177     safe_layout = document.textclass in safe_layouts
1178     if not safe_layout:
1179         document.warning("Lyx2lyx knows nothing about textclass '%s'. "
1180                          "Please check if short title insets have been converted correctly."
1181                          % document.textclass)
1182     # Do we use unsafe or unknown modules
1183     mods = document.get_module_list()
1184     unknown_modules = False
1185     used_caveat_modules = list()
1186     for mod in mods:
1187         if mod in safe_modules:
1188             continue
1189         if mod in caveat_modules:
1190             used_caveat_modules.append(mod)
1191             continue
1192         unknown_modules = True
1193         document.warning("Lyx2lyx knows nothing about module '%s'. "
1194                          "Please check if short title insets have been converted correctly."
1195                          % mod)
1196
1197     i = 0
1198     while True:
1199         i = find_token(document.body, "\\begin_inset Argument", i)
1200         if i == -1:
1201             return
1202
1203         if not safe_layout or unknown_modules:
1204             # We cannot do more here since we have no access to this layout.
1205             # InsetArgument itself will do the real work
1206             # (see InsetArgument::updateBuffer())
1207             document.body[i] = "\\begin_inset Argument 999"
1208             i = i + 1
1209             continue
1210         
1211         # Find containing paragraph layout
1212         parent = get_containing_layout(document.body, i)
1213         if parent == False:
1214             document.warning("Malformed lyx document: Can't find parent paragraph layout")
1215             i = i + 1
1216             continue
1217         parbeg = parent[1]
1218         parend = parent[2]
1219         allowed_opts = -1
1220         first_req = -1
1221         if len(used_caveat_modules) > 0:
1222             # We know for now that this must be the initials module with the Initial layout
1223             # If we get more such modules, we need some automating.
1224             if parent[0] == "Initial":
1225                 # Layout has 1 opt and 1 req arg.
1226                 # Count the actual arguments
1227                 actualargs = 0
1228                 for p in range(parbeg, parend):
1229                     if document.body[p] == "\\begin_inset Argument":
1230                         actualargs += 1
1231                 if actualargs == 1:
1232                     allowed_opts = 0
1233                     first_req = 2
1234         # Collect all arguments in this paragraph
1235         argnr = 0
1236         for p in range(parbeg, parend):
1237             if document.body[p] == "\\begin_inset Argument":
1238                 argnr += 1
1239                 if allowed_opts != -1:
1240                     # We have less arguments than opt + required.
1241                     # required must take precedence.
1242                     if argnr > allowed_opts and argnr < first_req:
1243                         argnr = first_req
1244                 document.body[p] = "\\begin_inset Argument %d" % argnr
1245         i = i + 1
1246
1247
1248 def revert_latexargs(document):
1249     " Revert InsetArgument to old syntax "
1250
1251     i = 0
1252     rx = re.compile(r'^\\begin_inset Argument (\d+)$')
1253     args = dict()
1254     while True:
1255         # Search for Argument insets
1256         i = find_token(document.body, "\\begin_inset Argument", i)
1257         if i == -1:
1258             return
1259         m = rx.match(document.body[i])
1260         if not m:
1261             # No ID: inset already reverted
1262             i = i + 1
1263             continue
1264         # Find containing paragraph layout
1265         parent = get_containing_layout(document.body, i)
1266         if parent == False:
1267             document.warning("Malformed lyx document: Can't find parent paragraph layout")
1268             i = i + 1
1269             continue
1270         parbeg = parent[1]
1271         parend = parent[2]
1272         realparbeg = parent[3]
1273         # Collect all arguments in this paragraph 
1274         realparend = parend
1275         for p in range(parbeg, parend):
1276             m = rx.match(document.body[p])
1277             if m:
1278                 val = int(m.group(1))
1279                 j = find_end_of_inset(document.body, p)
1280                 # Revert to old syntax
1281                 document.body[p] = "\\begin_inset Argument"
1282                 if j == -1:
1283                     document.warning("Malformed lyx document: Can't find end of Argument inset")
1284                     continue
1285                 if val > 0:
1286                     args[val] = document.body[p : j + 1]
1287                 # Adjust range end
1288                 realparend = realparend - len(document.body[p : j + 1])
1289                 # Remove arg inset at this position
1290                 del document.body[p : j + 1]
1291             if p >= realparend:
1292                 break
1293         # Now sort the arg insets
1294         subst = [""]
1295         for f in sorted(args):
1296             subst += args[f]
1297             del args[f]
1298         # Insert the sorted arg insets at paragraph begin
1299         document.body[realparbeg : realparbeg] = subst
1300
1301         i = realparbeg + 1 + len(subst)
1302
1303
1304 def revert_Argument_to_TeX_brace(document, line, n, nmax, environment):
1305     '''
1306     Reverts an InsetArgument to TeX-code
1307     usage:
1308     revert_Argument_to_TeX_brace(document, LineOfBeginLayout, StartArgument, EndArgument, isEnvironment)
1309     LineOfBeginLayout is the line  of the \begin_layout statement
1310     StartArgument is the number of the first argument that needs to be converted
1311     EndArgument is the number of the last argument that needs to be converted or the last defined one
1312     isEnvironment must be true, if the layout id for a LaTeX environment
1313     '''
1314     lineArg = 0
1315     while lineArg != -1 and n < nmax + 1:
1316       lineArg = find_token(document.body, "\\begin_inset Argument " + str(n), line)
1317       if lineArg != -1:
1318         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
1319         # we have to assure that no other inset is in the Argument
1320         beginInset = find_token(document.body, "\\begin_inset", beginPlain)
1321         endInset = find_token(document.body, "\\end_inset", beginPlain)
1322         k = beginPlain + 1
1323         l = k
1324         while beginInset < endInset and beginInset != -1:
1325           beginInset = find_token(document.body, "\\begin_inset", k)
1326           endInset = find_token(document.body, "\\end_inset", l)
1327           k = beginInset + 1
1328           l = endInset + 1
1329         if environment == False:
1330           document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}{")
1331           del(document.body[lineArg : beginPlain + 1])
1332         else:
1333           document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}")
1334           document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("{")
1335         n = n + 1
1336
1337
1338 def revert_IEEEtran(document):
1339   '''
1340   Reverts InsetArgument of
1341   Page headings
1342   Biography
1343   Biography without photo
1344   to TeX-code
1345   '''
1346   if document.textclass == "IEEEtran":
1347     i = 0
1348     j = 0
1349     k = 0
1350     while True:
1351       if i != -1:
1352         i = find_token(document.body, "\\begin_layout Page headings", i)
1353       if i != -1:
1354         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1355         i = i + 1
1356       if j != -1:
1357         j = find_token(document.body, "\\begin_layout Biography without photo", j)
1358       if j != -1:
1359         revert_Argument_to_TeX_brace(document, j, 1, 1, True)
1360         j = j + 1
1361       if k != -1:
1362         k = find_token(document.body, "\\begin_layout Biography", k)
1363         kA = find_token(document.body, "\\begin_layout Biography without photo", k)
1364         if k == kA and k != -1:
1365           k = k + 1
1366           continue
1367       if k != -1:
1368         # start with the second argument, therefore 2
1369         revert_Argument_to_TeX_brace(document, k, 2, 2, True)
1370         k = k + 1
1371       if i == -1 and j == -1 and k == -1:
1372         return
1373
1374
1375 def convert_TeX_brace_to_Argument(document, line, n, nmax, inset, environment):
1376     '''
1377     Converts TeX code for mandatory arguments to an InsetArgument
1378     The conversion of TeX code for optional arguments must be done with another routine
1379     !!! Be careful if the braces are different in your case as expected here:
1380     - "}{" separates mandatory arguments of commands
1381     - "}" + "{" separates mandatory arguments of commands
1382     - "}" + " " + "{" separates mandatory arguments of commands
1383     - { and } surround a mandatory argument of an environment
1384     usage:
1385     convert_TeX_brace_to_Argument(document, LineOfBeginLayout/Inset, StartArgument, EndArgument, isInset, isEnvironment)
1386     LineOfBeginLayout/Inset is the line  of the \begin_layout or \begin_inset statement
1387     StartArgument is the number of the first ERT that needs to be converted
1388     EndArgument is the number of the last ERT that needs to be converted
1389     isInset must be true, if braces inside an InsetLayout needs to be converted
1390     isEnvironment must be true, if the layout is for a LaTeX environment
1391     
1392     Todo: this routine can currently handle only one mandatory argument of environments
1393     '''
1394     lineERT = line
1395     endn = line
1396     loop = 1
1397     while lineERT != -1 and n < nmax + 1:
1398       lineERT = find_token(document.body, "\\begin_inset ERT", lineERT)
1399       if environment == False and lineERT != -1:
1400         bracePair = find_token(document.body, "}{", lineERT)
1401         # assure that the "}{" is in this ERT
1402         if bracePair == lineERT + 5:
1403           end = find_token(document.body, "\\end_inset", bracePair)
1404           document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
1405           if loop == 1:
1406             # in the case that n > 1 we have optional arguments before
1407             # therefore detect them if any
1408             if n > 1:
1409               # first check if there is an argument
1410               lineArg = find_token(document.body, "\\begin_inset Argument", line)
1411               if lineArg < lineERT and lineArg != -1:
1412                 # we have an argument, so now search backwards for its end
1413                 # we must now assure that we don't find other insets like e.g. a newline
1414                 endInsetArg = lineERT
1415                 endLayoutArg = endInsetArg
1416                 while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
1417                   endInsetArg = endInsetArg - 1
1418                   endLayoutArg = endInsetArg
1419                   endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
1420                   endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
1421                 line = endInsetArg + 1
1422             if inset == False:
1423               document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1424             else:
1425               document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1426           else:
1427             document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1428           n = n + 1
1429           endn = end
1430           loop = loop + 1
1431         # now check the case that we have "}" + "{" in two ERTs
1432         else:
1433           endBrace = find_token(document.body, "}", lineERT)
1434           if endBrace == lineERT + 5:
1435             beginBrace = find_token(document.body, "{", endBrace)
1436             # assure that the ERTs are consecutive (11 or 12 depending if there is a space between the ERTs or not)
1437             if beginBrace == endBrace + 11 or beginBrace == endBrace + 12:
1438               end = find_token(document.body, "\\end_inset", beginBrace)
1439               document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
1440               if loop == 1:
1441                 # in the case that n > 1 we have optional arguments before
1442                 # therefore detect them if any
1443                 if n > 1:
1444                   # first check if there is an argument
1445                   lineArg = find_token(document.body, "\\begin_inset Argument", line)
1446                   if lineArg < lineERT and lineArg != -1:
1447                     # we have an argument, so now search backwards for its end
1448                     # we must now assure that we don't find other insets like e.g. a newline
1449                     endInsetArg = lineERT
1450                     endLayoutArg = endInsetArg
1451                     while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
1452                       endInsetArg = endInsetArg - 1
1453                       endLayoutArg = endInsetArg
1454                       endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
1455                       endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
1456                     line = endInsetArg + 1
1457                 if inset == False:
1458                   document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1459                 else:
1460                   document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1461               else:
1462                 document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1463               n = n + 1
1464               loop = loop + 1
1465               # set the line where the next argument will be inserted
1466               if beginBrace == endBrace + 11:
1467                 endn = end - 11
1468               else:
1469                 endn = end - 12
1470           else:
1471             lineERT = lineERT + 1
1472       if environment == True and lineERT != -1:
1473         opening = find_token(document.body, "{", lineERT)
1474         if opening == lineERT + 5: # assure that the "{" is in this ERT
1475           end = find_token(document.body, "\\end_inset", opening)
1476           document.body[lineERT : end + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1477           n = n + 1
1478           lineERT2 = find_token(document.body, "\\begin_inset ERT", lineERT)
1479           closing = find_token(document.body, "}", lineERT2)
1480           if closing == lineERT2 + 5: # assure that the "}" is in this ERT
1481             end2 = find_token(document.body, "\\end_inset", closing)
1482             document.body[lineERT2 : end2 + 1] = ["\\end_layout", "", "\\end_inset"]
1483         else:
1484           lineERT = lineERT + 1
1485
1486
1487 def convert_IEEEtran(document):
1488   '''
1489   Converts ERT of
1490   Page headings
1491   Biography
1492   Biography without photo
1493   to InsetArgument
1494   '''
1495   if document.textclass == "IEEEtran":
1496     i = 0
1497     j = 0
1498     k = 0
1499     while True:
1500       if i != -1:
1501         i = find_token(document.body, "\\begin_layout Page headings", i)
1502       if i != -1:
1503         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1504         i = i + 1
1505       if j != -1:
1506         j = find_token(document.body, "\\begin_layout Biography without photo", j)
1507       if j != -1:
1508         convert_TeX_brace_to_Argument(document, j, 1, 1, False, True)
1509         j = j + 1
1510       if k != -1:
1511         # assure that we don't handle Biography Biography without photo
1512         k = find_token(document.body, "\\begin_layout Biography", k)
1513         kA = find_token(document.body, "\\begin_layout Biography without photo", k - 1)
1514       if k == kA and k != -1:
1515         k = k + 1
1516         continue
1517       if k != -1:
1518         # the argument we want to convert is the second one
1519         convert_TeX_brace_to_Argument(document, k, 2, 2, False, True)
1520         k = k + 1
1521       if i == -1 and j == -1 and k == -1:
1522         return
1523
1524
1525 def revert_AASTeX(document):
1526   " Reverts InsetArgument of Altaffilation to TeX-code "
1527   if document.textclass == "aastex":
1528     i = 0
1529     while True:
1530       if i != -1:
1531         i = find_token(document.body, "\\begin_layout Altaffilation", i)
1532       if i != -1:
1533         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1534         i = i + 1
1535       if i == -1:
1536         return
1537
1538
1539 def convert_AASTeX(document):
1540   " Converts ERT of Altaffilation to InsetArgument "
1541   if document.textclass == "aastex":
1542     i = 0
1543     while True:
1544       if i != -1:
1545         i = find_token(document.body, "\\begin_layout Altaffilation", i)
1546       if i != -1:
1547         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1548         i = i + 1
1549       if i == -1:
1550         return
1551
1552
1553 def revert_AGUTeX(document):
1554   " Reverts InsetArgument of Author affiliation to TeX-code "
1555   if document.textclass == "agutex":
1556     i = 0
1557     while True:
1558       if i != -1:
1559         i = find_token(document.body, "\\begin_layout Author affiliation", i)
1560       if i != -1:
1561         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1562         i = i + 1
1563       if i == -1:
1564         return
1565
1566
1567 def convert_AGUTeX(document):
1568   " Converts ERT of Author affiliation to InsetArgument "
1569   if document.textclass == "agutex":
1570     i = 0
1571     while True:
1572       if i != -1:
1573         i = find_token(document.body, "\\begin_layout Author affiliation", i)
1574       if i != -1:
1575         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1576         i = i + 1
1577       if i == -1:
1578         return
1579
1580
1581 def revert_IJMP(document):
1582   " Reverts InsetArgument of MarkBoth to TeX-code "
1583   if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1584     i = 0
1585     while True:
1586       if i != -1:
1587         i = find_token(document.body, "\\begin_layout MarkBoth", i)
1588       if i != -1:
1589         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1590         i = i + 1
1591       if i == -1:
1592         return
1593
1594
1595 def convert_IJMP(document):
1596   " Converts ERT of MarkBoth to InsetArgument "
1597   if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1598     i = 0
1599     while True:
1600       if i != -1:
1601         i = find_token(document.body, "\\begin_layout MarkBoth", i)
1602       if i != -1:
1603         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1604         i = i + 1
1605       if i == -1:
1606         return
1607
1608
1609 def revert_SIGPLAN(document):
1610   " Reverts InsetArgument of MarkBoth to TeX-code "
1611   if document.textclass == "sigplanconf":
1612     i = 0
1613     j = 0
1614     while True:
1615       if i != -1:
1616         i = find_token(document.body, "\\begin_layout Conference", i)
1617       if i != -1:
1618         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1619         i = i + 1
1620       if j != -1:
1621         j = find_token(document.body, "\\begin_layout Author", j)
1622       if j != -1:
1623         revert_Argument_to_TeX_brace(document, j, 1, 2, False)
1624         j = j + 1
1625       if i == -1 and j == -1:
1626         return
1627
1628
1629 def convert_SIGPLAN(document):
1630   " Converts ERT of MarkBoth to InsetArgument "
1631   if document.textclass == "sigplanconf":
1632     i = 0
1633     j = 0
1634     while True:
1635       if i != -1:
1636         i = find_token(document.body, "\\begin_layout Conference", i)
1637       if i != -1:
1638         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1639         i = i + 1
1640       if j != -1:
1641         j = find_token(document.body, "\\begin_layout Author", j)
1642       if j != -1:
1643         convert_TeX_brace_to_Argument(document, j, 1, 2, False, False)
1644         j = j + 1
1645       if i == -1 and j == -1:
1646         return
1647
1648
1649 def revert_SIGGRAPH(document):
1650   " Reverts InsetArgument of Flex CRcat to TeX-code "
1651   if document.textclass == "acmsiggraph":
1652     i = 0
1653     while True:
1654       if i != -1:
1655         i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1656       if i != -1:
1657         revert_Argument_to_TeX_brace(document, i, 1, 3, False)
1658         i = i + 1
1659       if i == -1:
1660         return
1661
1662
1663 def convert_SIGGRAPH(document):
1664   " Converts ERT of Flex CRcat to InsetArgument "
1665   if document.textclass == "acmsiggraph":
1666     i = 0
1667     while True:
1668       if i != -1:
1669         i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1670       if i != -1:
1671         convert_TeX_brace_to_Argument(document, i, 1, 3, True, False)
1672         i = i + 1
1673       if i == -1:
1674         return
1675
1676
1677 def revert_EuropeCV(document):
1678   " Reverts InsetArgument of Flex CRcat to TeX-code "
1679   if document.textclass == "europecv":
1680     i = 0
1681     j = 0
1682     k = 0
1683     m = 0
1684     while True:
1685       if i != -1:
1686         i = find_token(document.body, "\\begin_layout Item", i)
1687       if i != -1:
1688         revert_Argument_to_TeX_brace(document, i, 2, 2, False)
1689         i = i + 1
1690       if j != -1:
1691         j = find_token(document.body, "\\begin_layout BulletedItem", j)
1692       if j != -1:
1693         revert_Argument_to_TeX_brace(document, j, 2, 2, False)
1694         j = j + 1
1695       if k != -1:
1696         k = find_token(document.body, "\\begin_layout Language", k)
1697       if k != -1:
1698         revert_Argument_to_TeX_brace(document, k, 2, 6, False)
1699         k = k + 1
1700       if m != -1:
1701         m = find_token(document.body, "\\begin_layout LastLanguage", m)
1702       if m != -1:
1703         revert_Argument_to_TeX_brace(document, m, 2, 6, False)
1704         m = m + 1
1705       if i == -1 and j == -1 and k == -1 and m == -1:
1706         return
1707
1708
1709 def convert_EuropeCV(document):
1710   " Converts ERT of Flex CRcat to InsetArgument "
1711   if document.textclass == "europecv":
1712     i = 0
1713     j = 0
1714     k = 0
1715     m = 0
1716     while True:
1717       if i != -1:
1718         i = find_token(document.body, "\\begin_layout Item", i)
1719       if i != -1:
1720         convert_TeX_brace_to_Argument(document, i, 2, 2, False, False)
1721         i = i + 1
1722       if j != -1:
1723         j = find_token(document.body, "\\begin_layout BulletedItem", j)
1724       if j != -1:
1725         convert_TeX_brace_to_Argument(document, j, 2, 2, False, False)
1726         j = j + 1
1727       if k != -1:
1728         k = find_token(document.body, "\\begin_layout Language", k)
1729       if k != -1:
1730         convert_TeX_brace_to_Argument(document, k, 2, 6, False, False)
1731         k = k + 1
1732       if m != -1:
1733         m = find_token(document.body, "\\begin_layout LastLanguage", m)
1734       if m != -1:
1735         convert_TeX_brace_to_Argument(document, m, 2, 6, False, False)
1736         m = m + 1
1737       if i == -1 and j == -1 and k == -1 and m == -1:
1738         return
1739
1740
1741 def revert_literate(document):
1742     " Revert Literate document to old format "
1743     if del_token(document.header, "noweb", 0):
1744       document.textclass = "literate-" + document.textclass
1745       i = 0
1746       while True:
1747         i = find_token(document.body, "\\begin_layout Chunk", i)
1748         if i == -1:
1749           break
1750         document.body[i] = "\\begin_layout Scrap"
1751         i = i + 1
1752
1753
1754 def convert_literate(document):
1755     " Convert Literate document to new format"
1756     i = find_token(document.header, "\\textclass", 0)    
1757     if (i != -1) and "literate-" in document.header[i]:
1758       document.textclass = document.header[i].replace("\\textclass literate-", "")
1759       j = find_token(document.header, "\\begin_modules", 0)
1760       if (j != -1):
1761         document.header.insert(j + 1, "noweb")
1762       else:
1763         document.header.insert(i + 1, "\\end_modules")
1764         document.header.insert(i + 1, "noweb")
1765         document.header.insert(i + 1, "\\begin_modules")
1766       i = 0
1767       while True:
1768         i = find_token(document.body, "\\begin_layout Scrap", i)
1769         if i == -1:
1770           break
1771         document.body[i] = "\\begin_layout Chunk"
1772         i = i + 1
1773
1774
1775 def revert_itemargs(document):
1776     " Reverts \\item arguments to TeX-code "
1777     i = 0
1778     while True:
1779         i = find_token(document.body, "\\begin_inset Argument item:", i)
1780         if i == -1:
1781             return
1782         j = find_end_of_inset(document.body, i)
1783         # Find containing paragraph layout
1784         parent = get_containing_layout(document.body, i)
1785         if parent == False:
1786             document.warning("Malformed lyx document: Can't find parent paragraph layout")
1787             i = i + 1
1788             continue
1789         parbeg = parent[3]
1790         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
1791         endPlain = find_end_of_layout(document.body, beginPlain)
1792         content = document.body[beginPlain + 1 : endPlain]
1793         del document.body[i:j+1]
1794         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
1795         document.body[parbeg : parbeg] = subst
1796         i = i + 1
1797
1798
1799 def revert_garamondx_newtxmath(document):
1800     " Revert native garamond newtxmath definition to LaTeX " 
1801
1802     i = find_token(document.header, "\\font_math", 0)
1803     if i == -1:
1804        return
1805     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1806         val = get_value(document.header, "\\font_math", i)
1807         if val == "garamondx-ntxm":
1808             add_to_preamble(document, "\\usepackage[garamondx]{newtxmath}")
1809             document.header[i] = "\\font_math auto"
1810
1811
1812 def revert_garamondx(document):
1813     " Revert native garamond font definition to LaTeX " 
1814
1815     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1816         i = find_token(document.header, "\\font_roman garamondx", 0)
1817         if i != -1:
1818             osf = False
1819             j = find_token(document.header, "\\font_osf true", 0)
1820             if j != -1:
1821                 osf = True
1822             preamble = "\\usepackage"
1823             if osf:
1824                 preamble += "[osfI]"
1825             preamble += "{garamondx}"
1826             add_to_preamble(document, [preamble])
1827             document.header[i] = "\\font_roman default"
1828
1829
1830 def convert_beamerargs(document):
1831     " Converts beamer arguments to new layout "
1832     
1833     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
1834     if document.textclass not in beamer_classes:
1835         return
1836
1837     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
1838     list_layouts = ["Itemize", "Enumerate", "Description"]
1839     rx = re.compile(r'^\\begin_inset Argument (\d+)$')
1840
1841     i = 0
1842     while True:
1843         i = find_token(document.body, "\\begin_inset Argument", i)
1844         if i == -1:
1845             return
1846         # Find containing paragraph layout
1847         parent = get_containing_layout(document.body, i)
1848         if parent == False:
1849             document.warning("Malformed lyx document: Can't find parent paragraph layout")
1850             i = i + 1
1851             continue
1852         parbeg = parent[1]
1853         parend = parent[2]
1854         layoutname = parent[0]
1855         for p in range(parbeg, parend):
1856             if layoutname in shifted_layouts:
1857                 m = rx.match(document.body[p])
1858                 if m:
1859                     argnr = int(m.group(1))
1860                     argnr += 1
1861                     document.body[p] = "\\begin_inset Argument %d" % argnr
1862             if layoutname == "AgainFrame":
1863                 m = rx.match(document.body[p])
1864                 if m:
1865                     document.body[p] = "\\begin_inset Argument 3"
1866                     if document.body[p + 4] == "\\begin_inset ERT":
1867                         if document.body[p + 9].startswith("<"):
1868                             # This is an overlay specification
1869                             # strip off the <
1870                             document.body[p + 9] = document.body[p + 9][1:]
1871                             if document.body[p + 9].endswith(">"):
1872                                 # strip off the >
1873                                 document.body[p + 9] = document.body[p + 9][:-1]
1874                                 # Shift this one
1875                                 document.body[p] = "\\begin_inset Argument 2"
1876             if layoutname in list_layouts:
1877                 m = rx.match(document.body[p])
1878                 if m:
1879                     if m.group(1) == "1":
1880                         if document.body[p + 4] == "\\begin_inset ERT":
1881                             if document.body[p + 9].startswith("<"):
1882                                 # This is an overlay specification
1883                                 # strip off the <
1884                                 document.body[p + 9] = document.body[p + 9][1:]
1885                                 if document.body[p + 9].endswith(">"):
1886                                     # strip off the >
1887                                     document.body[p + 9] = document.body[p + 9][:-1]
1888                         elif layoutname != "Itemize":
1889                             # Shift this one
1890                             document.body[p] = "\\begin_inset Argument 2"
1891         i = i + 1
1892
1893
1894 def convert_againframe_args(document):
1895     " Converts beamer AgainFrame to new layout "
1896
1897     # FIXME: This currently only works if the arguments are in one single ERT
1898     
1899     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
1900     if document.textclass not in beamer_classes:
1901         return
1902    
1903     i = 0
1904     while True:
1905         i = find_token(document.body, "\\begin_layout AgainFrame", i)
1906         if i == -1:
1907             break
1908         parent = get_containing_layout(document.body, i)
1909         if parent[1] != i:
1910             document.warning("Wrong parent layout!")
1911         j = parent[2]
1912         parbeg = parent[3]
1913         if i != -1:
1914             if document.body[parbeg] == "\\begin_inset ERT":
1915                 ertcont = parbeg + 5
1916                 if document.body[ertcont].startswith("[<"):
1917                     # This is a default overlay specification
1918                     # strip off the [<
1919                     document.body[ertcont] = document.body[ertcont][2:]
1920                     if document.body[ertcont].endswith(">]"):
1921                         # strip off the >]
1922                         document.body[ertcont] = document.body[ertcont][:-2]
1923                     elif document.body[ertcont].endswith("]"):
1924                         # divide the args
1925                         tok = document.body[ertcont].find('>][')
1926                         if tok != -1:
1927                             subst = [document.body[ertcont][:tok],
1928                                      '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
1929                                      'status collapsed', '', '\\begin_layout Plain Layout',
1930                                      document.body[ertcont][tok + 3:-1]]
1931                             document.body[ertcont : ertcont + 1] = subst
1932                      # Convert to ArgInset
1933                     document.body[parbeg] = "\\begin_inset Argument 2"
1934                     i = j
1935                     continue
1936                 elif document.body[ertcont].startswith("<"):
1937                     # This is an overlay specification
1938                     # strip off the <
1939                     document.body[ertcont] = document.body[ertcont][1:]
1940                     if document.body[ertcont].endswith(">"):
1941                         # strip off the >
1942                         document.body[ertcont] = document.body[ertcont][:-1]
1943                         # Convert to ArgInset
1944                         document.body[parbeg] = "\\begin_inset Argument 1"
1945                     elif document.body[ertcont].endswith(">]"):
1946                         # divide the args
1947                         tok = document.body[ertcont].find('>[<')
1948                         if tok != -1:
1949                            document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
1950                                                            '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
1951                                                            'status collapsed', '', '\\begin_layout Plain Layout',
1952                                                            document.body[ertcont][tok + 3:-2]]
1953                         # Convert to ArgInset
1954                         document.body[parbeg] = "\\begin_inset Argument 1"
1955                     elif document.body[ertcont].endswith("]"):
1956                         # divide the args
1957                         tok = document.body[ertcont].find('>[<')
1958                         if tok != -1:
1959                            # divide the args
1960                            tokk = document.body[ertcont].find('>][')
1961                            if tokk != -1:
1962                                document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
1963                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
1964                                                                'status collapsed', '', '\\begin_layout Plain Layout',
1965                                                                document.body[ertcont][tok + 3:tokk],
1966                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
1967                                                                'status collapsed', '', '\\begin_layout Plain Layout',
1968                                                                document.body[ertcont][tokk + 3:-1]]
1969                         else:
1970                             tokk = document.body[ertcont].find('>[')
1971                             if tokk != -1:
1972                                 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tokk],
1973                                                                 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
1974                                                                 'status collapsed', '', '\\begin_layout Plain Layout',
1975                                                                 document.body[ertcont][tokk + 2:-1]]
1976                         # Convert to ArgInset
1977                         document.body[parbeg] = "\\begin_inset Argument 1"
1978                     i = j
1979                     continue
1980                 elif document.body[ertcont].startswith("["):
1981                     # This is an ERT option
1982                     # strip off the [
1983                     document.body[ertcont] = document.body[ertcont][1:]
1984                     if document.body[ertcont].endswith("]"):
1985                         # strip off the ]
1986                         document.body[ertcont] = document.body[ertcont][:-1]
1987                         # Convert to ArgInset
1988                         document.body[parbeg] = "\\begin_inset Argument 3"
1989                     i = j
1990                     continue
1991         i = j
1992
1993
1994 def convert_corollary_args(document):
1995     " Converts beamer corrolary-style ERT arguments native InsetArgs "
1996     
1997     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
1998     if document.textclass not in beamer_classes:
1999         return
2000    
2001     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2002     for lay in corollary_layouts:
2003         i = 0
2004         while True:
2005             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2006             if i == -1:
2007                 break
2008             parent = get_containing_layout(document.body, i)
2009             if parent[1] != i:
2010                 document.warning("Wrong parent layout!")
2011             j = parent[2]
2012             parbeg = parent[3]
2013             if i != -1:
2014                 if document.body[parbeg] == "\\begin_inset ERT":
2015                     ertcont = parbeg + 5
2016                     if document.body[ertcont].startswith("<"):
2017                         # This is an overlay specification
2018                         # strip off the <
2019                         document.body[ertcont] = document.body[ertcont][1:]
2020                         if document.body[ertcont].endswith(">"):
2021                             # strip off the >
2022                             document.body[ertcont] = document.body[ertcont][:-1]
2023                         elif document.body[ertcont].endswith("]"):
2024                             # divide the args
2025                             tok = document.body[ertcont].find('>[')
2026                             if tok != -1:
2027                                 subst = [document.body[ertcont][:tok],
2028                                          '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2029                                          'status collapsed', '', '\\begin_layout Plain Layout',
2030                                          document.body[ertcont][tok + 2:-1]]
2031                                 document.body[ertcont : ertcont + 1] = subst
2032                         # Convert to ArgInset
2033                         document.body[parbeg] = "\\begin_inset Argument 1"
2034                         i = j
2035                         continue
2036                     elif document.body[ertcont].startswith("["):
2037                         # This is an ERT option
2038                         # strip off the [
2039                         document.body[ertcont] = document.body[ertcont][1:]
2040                         if document.body[ertcont].endswith("]"):
2041                             # strip off the ]
2042                             document.body[ertcont] = document.body[ertcont][:-1]
2043                         # Convert to ArgInset
2044                         document.body[parbeg] = "\\begin_inset Argument 2"
2045                     i = j
2046                     continue
2047             i = j
2048
2049
2050
2051 def convert_quote_args(document):
2052     " Converts beamer quote style ERT args to native InsetArgs "
2053     
2054     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2055     if document.textclass not in beamer_classes:
2056         return
2057    
2058     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2059     for lay in quote_layouts:
2060         i = 0
2061         while True:
2062             i = find_token(document.body, "\\begin_layout " + lay, i)
2063             if i == -1:
2064                 break
2065             parent = get_containing_layout(document.body, i)
2066             if parent[1] != i:
2067                 document.warning("Wrong parent layout!")
2068             j = parent[2]
2069             parbeg = parent[3]
2070             if i != -1:
2071                 if document.body[parbeg] == "\\begin_inset ERT":
2072                     if document.body[i + 6].startswith("<"):
2073                         # This is an overlay specification
2074                         # strip off the <
2075                         document.body[i + 6] = document.body[i + 6][1:]
2076                         if document.body[i + 6].endswith(">"):
2077                             # strip off the >
2078                             document.body[i + 6] = document.body[i + 6][:-1]
2079                             # Convert to ArgInset
2080                             document.body[i + 1] = "\\begin_inset Argument 1"
2081             i = j
2082
2083
2084 def revert_beamerargs(document):
2085     " Reverts beamer arguments to old layout "
2086     
2087     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2088     if document.textclass not in beamer_classes:
2089         return
2090
2091     i = 0
2092     list_layouts = ["Itemize", "Enumerate", "Description"]
2093     headings = ["Part", "Section", "Section*", "Subsection", "Subsection*",
2094                 "Subsubsection", "Subsubsection*", "FrameSubtitle", "NoteItem"]
2095     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2096     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2097     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2098
2099     while True:
2100         i = find_token(document.body, "\\begin_inset Argument", i)
2101         if i == -1:
2102             return
2103         # Find containing paragraph layout
2104         parent = get_containing_layout(document.body, i)
2105         if parent == False:
2106             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2107             i = i + 1
2108             continue
2109         parbeg = parent[1]
2110         parend = parent[2]
2111         realparbeg = parent[3]
2112         layoutname = parent[0]
2113         realparend = parend
2114         for p in range(parbeg, parend):
2115             if p >= realparend:
2116                 i = realparend
2117                 break
2118             if layoutname in headings:
2119                 m = rx.match(document.body[p])
2120                 if m:
2121                     argnr = m.group(1)
2122                     if argnr == "1":
2123                         # Find containing paragraph layout
2124                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2125                         endPlain = find_end_of_layout(document.body, beginPlain)
2126                         endInset = find_end_of_inset(document.body, p)
2127                         argcontent = document.body[beginPlain + 1 : endPlain]
2128                         # Adjust range end
2129                         realparend = realparend - len(document.body[p : endInset + 1])
2130                         # Remove arg inset
2131                         del document.body[p : endInset + 1]
2132                         if layoutname == "FrameSubtitle":
2133                             pre = put_cmd_in_ert("\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2134                         elif layoutname == "NoteItem":
2135                             pre = put_cmd_in_ert("\\note<") + argcontent + put_cmd_in_ert(">[item]")
2136                         elif layoutname.endswith('*'):
2137                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower()[:-1] + "<") + argcontent + put_cmd_in_ert(">*")
2138                         else:
2139                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2140                         secarg = find_token(document.body, "\\begin_inset Argument 2", parbeg, parend)
2141                         if secarg != -1:
2142                             # Find containing paragraph layout
2143                             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", secarg)
2144                             endPlain = find_end_of_layout(document.body, beginPlain)
2145                             endInset = find_end_of_inset(document.body, secarg)
2146                             argcontent = document.body[beginPlain + 1 : endPlain]
2147                             # Adjust range end
2148                             realparend = realparend - len(document.body[secarg : endInset + 1])
2149                             del document.body[secarg : endInset + 1]
2150                             pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2151                         pre += put_cmd_in_ert("{")
2152                         document.body[parbeg] = "\\begin_layout Standard"
2153                         document.body[realparbeg : realparbeg] = pre
2154                         pe = find_end_of_layout(document.body, parbeg)
2155                         post = put_cmd_in_ert("}")
2156                         document.body[pe : pe] = post
2157                         realparend += len(pre) + len(post)
2158             if layoutname == "AgainFrame":
2159                 m = rx.match(document.body[p])
2160                 if m:
2161                     argnr = m.group(1)
2162                     if argnr == "3":
2163                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2164                         endPlain = find_end_of_layout(document.body, beginPlain)
2165                         endInset = find_end_of_inset(document.body, p)
2166                         content = document.body[beginPlain + 1 : endPlain]
2167                         # Adjust range end
2168                         realparend = realparend - len(document.body[p : endInset + 1])
2169                         # Remove arg inset
2170                         del document.body[p : endInset + 1]
2171                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2172                         document.body[realparbeg : realparbeg] = subst
2173             if layoutname == "Overprint":
2174                 m = rx.match(document.body[p])
2175                 if m:
2176                     argnr = m.group(1)
2177                     if argnr == "1":
2178                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2179                         endPlain = find_end_of_layout(document.body, beginPlain)
2180                         endInset = find_end_of_inset(document.body, p)
2181                         content = document.body[beginPlain + 1 : endPlain]
2182                         # Adjust range end
2183                         realparend = realparend - len(document.body[p : endInset + 1])
2184                         # Remove arg inset
2185                         del document.body[p : endInset + 1]
2186                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2187                         document.body[realparbeg : realparbeg] = subst
2188             if layoutname == "OverlayArea":
2189                 m = rx.match(document.body[p])
2190                 if m:
2191                     argnr = m.group(1)
2192                     if argnr == "2":
2193                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2194                         endPlain = find_end_of_layout(document.body, beginPlain)
2195                         endInset = find_end_of_inset(document.body, p)
2196                         content = document.body[beginPlain + 1 : endPlain]
2197                         # Adjust range end
2198                         realparend = realparend - len(document.body[p : endInset + 1])
2199                         # Remove arg inset
2200                         del document.body[p : endInset + 1]
2201                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2202                         document.body[realparbeg : realparbeg] = subst
2203             if layoutname in list_layouts:
2204                 m = rx.match(document.body[p])
2205                 if m:
2206                     argnr = m.group(1)
2207                     if argnr == "1":
2208                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2209                         endPlain = find_end_of_layout(document.body, beginPlain)
2210                         endInset = find_end_of_inset(document.body, p)
2211                         content = document.body[beginPlain + 1 : endPlain]
2212                         # Adjust range end
2213                         realparend = realparend - len(document.body[p : endInset + 1])
2214                         # Remove arg inset
2215                         del document.body[p : endInset + 1]
2216                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2217                         document.body[realparbeg : realparbeg] = subst
2218                     elif argnr == "item:1":
2219                         j = find_end_of_inset(document.body, i)
2220                         # Find containing paragraph layout
2221                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2222                         endPlain = find_end_of_layout(document.body, beginPlain)
2223                         content = document.body[beginPlain + 1 : endPlain]
2224                         del document.body[i:j+1]
2225                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2226                         document.body[realparbeg : realparbeg] = subst
2227                     elif argnr == "item:2":
2228                         j = find_end_of_inset(document.body, i)
2229                         # Find containing paragraph layout
2230                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2231                         endPlain = find_end_of_layout(document.body, beginPlain)
2232                         content = document.body[beginPlain + 1 : endPlain]
2233                         del document.body[i:j+1]
2234                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2235                         document.body[realparbeg : realparbeg] = subst
2236             if layoutname in quote_layouts:
2237                 m = rx.match(document.body[p])
2238                 if m:
2239                     argnr = m.group(1)
2240                     if argnr == "1":
2241                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2242                         endPlain = find_end_of_layout(document.body, beginPlain)
2243                         endInset = find_end_of_inset(document.body, p)
2244                         content = document.body[beginPlain + 1 : endPlain]
2245                         # Adjust range end
2246                         realparend = realparend - len(document.body[p : endInset + 1])
2247                         # Remove arg inset
2248                         del document.body[p : endInset + 1]
2249                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2250                         document.body[realparbeg : realparbeg] = subst
2251             if layoutname in corollary_layouts:
2252                 m = rx.match(document.body[p])
2253                 if m:
2254                     argnr = m.group(1)
2255                     if argnr == "2":
2256                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2257                         endPlain = find_end_of_layout(document.body, beginPlain)
2258                         endInset = find_end_of_inset(document.body, p)
2259                         content = document.body[beginPlain + 1 : endPlain]
2260                         # Adjust range end
2261                         realparend = realparend - len(document.body[p : endInset + 1])
2262                         # Remove arg inset
2263                         del document.body[p : endInset + 1]
2264                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2265                         document.body[realparbeg : realparbeg] = subst
2266         
2267         i = realparend
2268
2269
2270 def revert_beamerargs2(document):
2271     " Reverts beamer arguments to old layout, step 2 "
2272     
2273     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2274     if document.textclass not in beamer_classes:
2275         return
2276
2277     i = 0
2278     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2279     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2280     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2281
2282     while True:
2283         i = find_token(document.body, "\\begin_inset Argument", i)
2284         if i == -1:
2285             return
2286         # Find containing paragraph layout
2287         parent = get_containing_layout(document.body, i)
2288         if parent == False:
2289             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2290             i = i + 1
2291             continue
2292         parbeg = parent[1]
2293         parend = parent[2]
2294         realparbeg = parent[3]
2295         layoutname = parent[0]
2296         realparend = parend
2297         for p in range(parbeg, parend):
2298             if p >= realparend:
2299                 i = realparend
2300                 break
2301             if layoutname in shifted_layouts:
2302                 m = rx.match(document.body[p])
2303                 if m:
2304                     argnr = m.group(1)
2305                     if argnr == "2":
2306                         document.body[p] = "\\begin_inset Argument 1"       
2307             if layoutname in corollary_layouts:
2308                 m = rx.match(document.body[p])
2309                 if m:
2310                     argnr = m.group(1)
2311                     if argnr == "1":
2312                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2313                         endPlain = find_end_of_layout(document.body, beginPlain)
2314                         endInset = find_end_of_inset(document.body, p)
2315                         content = document.body[beginPlain + 1 : endPlain]
2316                         # Adjust range end
2317                         realparend = realparend - len(document.body[p : endInset + 1])
2318                         # Remove arg inset
2319                         del document.body[p : endInset + 1]
2320                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2321                         document.body[realparbeg : realparbeg] = subst
2322             if layoutname == "OverlayArea":
2323                 m = rx.match(document.body[p])
2324                 if m:
2325                     argnr = m.group(1)
2326                     if argnr == "1":
2327                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2328                         endPlain = find_end_of_layout(document.body, beginPlain)
2329                         endInset = find_end_of_inset(document.body, p)
2330                         content = document.body[beginPlain + 1 : endPlain]
2331                         # Adjust range end
2332                         realparend = realparend - len(document.body[p : endInset + 1])
2333                         # Remove arg inset
2334                         del document.body[p : endInset + 1]
2335                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2336                         document.body[realparbeg : realparbeg] = subst
2337             if layoutname == "AgainFrame":
2338                 m = rx.match(document.body[p])
2339                 if m:
2340                     argnr = m.group(1)
2341                     if argnr == "2":
2342                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2343                         endPlain = find_end_of_layout(document.body, beginPlain)
2344                         endInset = find_end_of_inset(document.body, p)
2345                         content = document.body[beginPlain + 1 : endPlain]
2346                         # Adjust range end
2347                         realparend = realparend - len(document.body[p : endInset + 1])
2348                         # Remove arg inset
2349                         del document.body[p : endInset + 1]
2350                         subst = put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
2351                         document.body[realparbeg : realparbeg] = subst
2352         i = realparend
2353
2354
2355 def revert_beamerargs3(document):
2356     " Reverts beamer arguments to old layout, step 3 "
2357     
2358     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2359     if document.textclass not in beamer_classes:
2360         return
2361
2362     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2363     i = 0
2364     while True:
2365         i = find_token(document.body, "\\begin_inset Argument", i)
2366         if i == -1:
2367             return
2368         # Find containing paragraph layout
2369         parent = get_containing_layout(document.body, i)
2370         if parent == False:
2371             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2372             i = i + 1
2373             continue
2374         parbeg = parent[1]
2375         parend = parent[2]
2376         realparbeg = parent[3]
2377         layoutname = parent[0]
2378         realparend = parend
2379         for p in range(parbeg, parend):
2380             if p >= realparend:
2381                 i = realparend
2382                 break
2383             if layoutname == "AgainFrame":
2384                 m = rx.match(document.body[p])
2385                 if m:
2386                     argnr = m.group(1)
2387                     if argnr == "1":
2388                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2389                         endPlain = find_end_of_layout(document.body, beginPlain)
2390                         endInset = find_end_of_inset(document.body, p)
2391                         content = document.body[beginPlain + 1 : endPlain]
2392                         # Adjust range end
2393                         realparend = realparend - len(document.body[p : endInset + 1])
2394                         # Remove arg inset
2395                         del document.body[p : endInset + 1]
2396                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2397                         document.body[realparbeg : realparbeg] = subst
2398         i = realparend
2399
2400
2401 def revert_beamerflex(document):
2402     " Reverts beamer Flex insets "
2403     
2404     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2405     if document.textclass not in beamer_classes:
2406         return
2407
2408     new_flexes = {"Emphasize" : "\\emph", "Only" : "\\only", "Uncover" : "\\uncover",
2409                   "Visible" : "\\visible", "Invisible" : "\\invisible",
2410                   "Alternative" : "\\alt", "Beamer_Note" : "\\note"}
2411     old_flexes = {"Alert" : "\\alert", "Structure" : "\\structure"}
2412     rx = re.compile(r'^\\begin_inset Flex (.+)$')
2413
2414     i = 0
2415     while True:
2416         i = find_token(document.body, "\\begin_inset Flex", i)
2417         if i == -1:
2418             return
2419         m = rx.match(document.body[i])
2420         if m:
2421             flextype = m.group(1)
2422             z = find_end_of_inset(document.body, i)
2423             if z == -1:
2424                 document.warning("Can't find end of Flex " + flextype + " inset.")
2425                 i += 1
2426                 continue
2427             if flextype in new_flexes:
2428                 pre = put_cmd_in_ert(new_flexes[flextype])
2429                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2430                 if arg != -1:
2431                     argend = find_end_of_inset(document.body, arg)
2432                     if argend == -1:
2433                         document.warning("Can't find end of Argument!")
2434                         i += 1
2435                         continue
2436                     # Find containing paragraph layout
2437                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2438                     endPlain = find_end_of_layout(document.body, beginPlain)
2439                     argcontent = document.body[beginPlain + 1 : endPlain]
2440                     # Adjust range end
2441                     z = z - len(document.body[arg : argend + 1])
2442                     # Remove arg inset
2443                     del document.body[arg : argend + 1]
2444                     pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2445                 arg = find_token(document.body, "\\begin_inset Argument 2", i, z)
2446                 if arg != -1:
2447                     argend = find_end_of_inset(document.body, arg)
2448                     if argend == -1:
2449                         document.warning("Can't find end of Argument!")
2450                         i += 1
2451                         continue
2452                     # Find containing paragraph layout
2453                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2454                     endPlain = find_end_of_layout(document.body, beginPlain)
2455                     argcontent = document.body[beginPlain + 1 : endPlain]
2456                     # Adjust range end
2457                     z = z - len(document.body[arg : argend + 1])
2458                     # Remove arg inset
2459                     del document.body[arg : argend + 1]
2460                     pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2461                 pre += put_cmd_in_ert("{")
2462                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2463                 endPlain = find_end_of_layout(document.body, beginPlain)
2464                 # Adjust range end
2465                 z = z - len(document.body[i : beginPlain + 1])
2466                 z += len(pre)
2467                 document.body[i : beginPlain + 1] = pre
2468                 post = put_cmd_in_ert("}")
2469                 document.body[z - 2 : z + 1] = post
2470             elif flextype in old_flexes:
2471                 pre = put_cmd_in_ert(old_flexes[flextype])
2472                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2473                 if arg == -1:
2474                     i += 1
2475                     continue
2476                 argend = find_end_of_inset(document.body, arg)
2477                 if argend == -1:
2478                     document.warning("Can't find end of Argument!")
2479                     i += 1
2480                     continue
2481                 # Find containing paragraph layout
2482                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2483                 endPlain = find_end_of_layout(document.body, beginPlain)
2484                 argcontent = document.body[beginPlain + 1 : endPlain]
2485                 # Adjust range end
2486                 z = z - len(document.body[arg : argend + 1])
2487                 # Remove arg inset
2488                 del document.body[arg : argend + 1]
2489                 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2490                 pre += put_cmd_in_ert("{")
2491                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2492                 endPlain = find_end_of_layout(document.body, beginPlain)
2493                 # Adjust range end
2494                 z = z - len(document.body[i : beginPlain + 1])
2495                 z += len(pre)
2496                 document.body[i : beginPlain + 1] = pre
2497                 post = put_cmd_in_ert("}")
2498                 document.body[z - 2 : z + 1] = post
2499         
2500         i += 1
2501
2502
2503 ##
2504 # Conversion hub
2505 #
2506
2507 supported_versions = ["2.1.0","2.1"]
2508 convert = [
2509            [414, []],
2510            [415, [convert_undertilde]],
2511            [416, []],
2512            [417, [convert_japanese_encodings]],
2513            [418, []],
2514            [419, []],
2515            [420, [convert_biblio_style]],
2516            [421, [convert_longtable_captions]],
2517            [422, [convert_use_packages]],
2518            [423, [convert_use_mathtools]],
2519            [424, [convert_cite_engine_type]],
2520            [425, []],
2521            [426, []],
2522            [427, []],
2523            [428, [convert_cell_rotation]],
2524            [429, [convert_table_rotation]],
2525            [430, [convert_listoflistings]],
2526            [431, [convert_use_amssymb]],
2527            [432, []],
2528            [433, [convert_armenian]],
2529            [434, []],
2530            [435, []],
2531            [436, []],
2532            [437, []],
2533            [438, []],
2534            [439, []],
2535            [440, []],
2536            [441, [convert_mdnomath]],
2537            [442, []],
2538            [443, []],
2539            [444, []],
2540            [445, []],
2541            [446, [convert_latexargs]],
2542            [447, [convert_IEEEtran, convert_AASTeX, convert_AGUTeX, convert_IJMP, convert_SIGPLAN, convert_SIGGRAPH, convert_EuropeCV]],
2543            [448, [convert_literate]],
2544            [449, []],
2545            [450, []],
2546            [451, [convert_beamerargs, convert_againframe_args, convert_corollary_args, convert_quote_args]]
2547           ]
2548
2549 revert =  [
2550            [450, [revert_beamerargs, revert_beamerargs2, revert_beamerargs3, revert_beamerflex]],
2551            [449, [revert_garamondx, revert_garamondx_newtxmath]],
2552            [448, [revert_itemargs]],
2553            [447, [revert_literate]],
2554            [446, [revert_IEEEtran, revert_AASTeX, revert_AGUTeX, revert_IJMP, revert_SIGPLAN, revert_SIGGRAPH, revert_EuropeCV]],
2555            [445, [revert_latexargs]],
2556            [444, [revert_uop]],
2557            [443, [revert_biolinum]],
2558            [442, []],
2559            [441, [revert_newtxmath]],
2560            [440, [revert_mdnomath]],
2561            [439, [revert_mathfonts]],
2562            [438, [revert_minionpro]],
2563            [437, [revert_ipadeco, revert_ipachar]],
2564            [436, [revert_texgyre]],
2565            [435, [revert_mathdesign]],
2566            [434, [revert_txtt]],
2567            [433, [revert_libertine]],
2568            [432, [revert_armenian]],
2569            [431, [revert_languages, revert_ancientgreek]],
2570            [430, [revert_use_amssymb]],
2571            [429, [revert_listoflistings]],
2572            [428, [revert_table_rotation]],
2573            [427, [revert_cell_rotation]],
2574            [426, [revert_tipa]],
2575            [425, [revert_verbatim]],
2576            [424, [revert_cancel]],
2577            [423, [revert_cite_engine_type]],
2578            [422, [revert_use_mathtools]],
2579            [421, [revert_use_packages]],
2580            [420, [revert_longtable_captions]],
2581            [419, [revert_biblio_style]],
2582            [418, [revert_australian]],
2583            [417, [revert_justification]],
2584            [416, [revert_japanese_encodings]],
2585            [415, [revert_negative_space, revert_math_spaces]],
2586            [414, [revert_undertilde]],
2587            [413, [revert_visible_space]]
2588           ]
2589
2590
2591 if __name__ == "__main__":
2592     pass