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