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