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