]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_1.py
e6d0bdca5bdee0d679f34a074666021e71510558
[lyx.git] / lib / lyx2lyx / lyx_2_1.py
1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # -*- coding: utf-8 -*-
4 # Copyright (C) 2011 The LyX team
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
20 """ Convert files to the file format generated by LyX 2.1"""
21
22 import re, string
23 import unicodedata
24 import sys, os
25
26 # Uncomment only what you need to import, please.
27
28 from parser_tools import count_pars_in_inset, del_token, find_token, find_token_exact, \
29     find_token_backwards, find_end_of, find_end_of_inset, find_end_of_layout, \
30     find_end_of_sequence, find_re, get_option_value, get_containing_layout, \
31     get_value, get_quoted_value, set_option_value
32
33 #from parser_tools import find_token, find_end_of, find_tokens, \
34   #find_end_of_inset, find_end_of_layout, \
35   #is_in_inset, del_token, check_token
36
37 from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, get_ert
38
39 #from lyx2lyx_tools import insert_to_preamble, \
40 #  lyx2latex, latex_length, revert_flex_inset, \
41 #  revert_font_attrs, hex2ratio, str2bool
42
43 ####################################################################
44 # Private helper functions
45
46 #def remove_option(lines, m, option):
47     #''' removes option from line m. returns whether we did anything '''
48     #l = lines[m].find(option)
49     #if l == -1:
50         #return False
51     #val = lines[m][l:].split('"')[1]
52     #lines[m] = lines[m][:l - 1] + lines[m][l+len(option + '="' + val + '"'):]
53     #return True
54
55
56 def revert_Argument_to_TeX_brace(document, line, endline, n, nmax, environment, opt):
57     '''
58     Reverts an InsetArgument to TeX-code
59     usage:
60     revert_Argument_to_TeX_brace(document, LineOfBegin, LineOfEnd, StartArgument, EndArgument, isEnvironment, isOpt)
61     LineOfBegin is the line  of the \begin_layout or \begin_inset statement
62     LineOfEnd is the line  of the \end_layout or \end_inset statement, if "0" is given, the end of the file is used instead
63     StartArgument is the number of the first argument that needs to be converted
64     EndArgument is the number of the last argument that needs to be converted or the last defined one
65     isEnvironment must be true, if the layout is for a LaTeX environment
66     isOpt must be true, if the argument is an optional one
67     '''
68     lineArg = 0
69     wasOpt = False
70     while lineArg != -1 and n < nmax + 1:
71       lineArg = find_token(document.body, "\\begin_inset Argument " + str(n), line)
72       if lineArg > endline and endline != 0:
73         return wasOpt
74       if lineArg != -1:
75         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
76         # we have to assure that no other inset is in the Argument
77         beginInset = find_token(document.body, "\\begin_inset", beginPlain)
78         endInset = find_token(document.body, "\\end_inset", beginPlain)
79         k = beginPlain + 1
80         l = k
81         while beginInset < endInset and beginInset != -1:
82           beginInset = find_token(document.body, "\\begin_inset", k)
83           endInset = find_token(document.body, "\\end_inset", l)
84           k = beginInset + 1
85           l = endInset + 1
86         if environment == False:
87           if opt == False:
88             document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}{")
89             del(document.body[lineArg : beginPlain + 1])
90             wasOpt = False
91           else:
92             document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("]")
93             document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("[")
94             wasOpt = True
95         else:
96           document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}")
97           document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("{")
98           wasOpt = False
99         n += 1
100     return wasOpt
101
102
103 def convert_TeX_brace_to_Argument(document, line, n, nmax, inset, environment, opt):
104     '''
105     Converts TeX code for mandatory arguments to an InsetArgument
106     The conversion of TeX code for optional arguments must be done with another routine
107     !!! Be careful if the braces are different in your case as expected here:
108     - "}{" separates mandatory arguments of commands
109     - "}" + "{" separates mandatory arguments of commands
110     - "}" + " " + "{" separates mandatory arguments of commands
111     - { and } surround a mandatory argument of an environment
112     usage:
113     convert_TeX_brace_to_Argument(document, LineOfBeginLayout/Inset, StartArgument, EndArgument, isInset, isEnvironment, isOpt)
114     LineOfBeginLayout/Inset is the line  of the \begin_layout or \begin_inset statement
115     StartArgument is the number of the first ERT that needs to be converted
116     EndArgument is the number of the last ERT that needs to be converted
117     isInset must be true, if braces inside an InsetLayout needs to be converted
118     isEnvironment must be true, if the layout is for a LaTeX environment
119     isOpt must be true, if the argument is an optional one
120     
121     Todo: this routine can currently handle only one mandatory argument of environments
122     '''
123
124     end_layout = find_end_of_layout(document.body, line)
125     lineERT = line
126     endn = line
127     loop = 1
128     while n < nmax + 1:
129       lineERT = find_token(document.body, "\\begin_inset ERT", lineERT, end_layout)
130       if lineERT == -1:
131         break
132       if environment == False:
133         end_ERT = find_end_of_inset(document.body, lineERT)
134         if end_ERT == -1:
135           document.warning("Can't find end of ERT!!")
136           break
137         # Note that this only checks for ][ or }{ at the beginning of a line
138         if opt:
139           bracePair = find_token(document.body, "][", lineERT, end_ERT)
140         else:
141           bracePair = find_token(document.body, "}{", lineERT, end_ERT)
142         if bracePair != -1:
143           end = find_token(document.body, "\\end_inset", bracePair)
144           document.body[lineERT : end_ERT + 1] = ["\\end_layout", "", "\\end_inset"]
145           if loop == 1:
146             # in the case that n > 1 we have optional arguments before
147             # therefore detect them if any
148             if n > 1:
149               # first check if there is an argument
150               lineArg = find_token(document.body, "\\begin_inset Argument", line)
151               if lineArg < lineERT and lineArg != -1:
152                 # we have an argument, so now search backwards for its end
153                 # we must now assure that we don't find other insets like e.g. a newline
154                 endInsetArg = lineERT
155                 endLayoutArg = endInsetArg
156                 while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
157                   endInsetArg = endInsetArg - 1
158                   endLayoutArg = endInsetArg
159                   endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
160                   endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
161                 line = endInsetArg + 1
162             if inset == False:
163               document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
164             else:
165               document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
166           else: # if loop != 1
167             document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
168           n += 1
169           endn = end
170           loop += 1
171         else: 
172           # no brace pair found
173           # now check the case that we have "}" + "{" in two ERTs
174           if opt:
175             endBrace = find_token(document.body, "]", lineERT, end_layout)
176           else:
177             endBrace = find_token(document.body, "}", lineERT, end_layout)
178           if endBrace == lineERT + 5:
179             if opt:
180               beginBrace = find_token(document.body, "[", endBrace, end_layout)
181             else:
182               beginBrace = find_token(document.body, "{", endBrace, end_layout)
183             # assure that the ERTs are consecutive (11 or 12 depending if there is a space between the ERTs or not)
184             if beginBrace == endBrace + 11 or beginBrace == endBrace + 12:
185               end = find_token(document.body, "\\end_inset", beginBrace)
186               document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
187               if loop == 1:
188                 # in the case that n > 1 we have optional arguments before
189                 # therefore detect them if any
190                 if n > 1:
191                   # first check if there is an argument
192                   lineArg = find_token(document.body, "\\begin_inset Argument", line)
193                   if lineArg < lineERT and lineArg != -1:
194                     # we have an argument, so now search backwards for its end
195                     # we must now assure that we don't find other insets like e.g. a newline
196                     endInsetArg = lineERT
197                     endLayoutArg = endInsetArg
198                     while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
199                       endInsetArg = endInsetArg - 1
200                       endLayoutArg = endInsetArg
201                       endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
202                       endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
203                     line = endInsetArg + 1
204                 if inset == False:
205                   document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
206                 else:
207                   document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
208               else:
209                 document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
210               n += 1
211               loop += 1
212               # set the line where the next argument will be inserted
213               if beginBrace == endBrace + 11:
214                 endn = end - 11
215               else:
216                 endn = end - 12
217             else:
218               lineERT += 1
219           else:
220             lineERT += 1
221       if environment == True:
222         end_ERT = find_end_of_inset(document.body, lineERT)
223         if end_ERT == -1:
224           document.warning("Can't find end of ERT!!")
225           break
226         # Note that this only checks for [ or { at the beginning of a line
227         if opt:
228           opening = find_token(document.body, "[", lineERT, end_ERT)
229         else:
230           opening = find_token(document.body, "{", lineERT, end_ERT)
231         if opening != -1:
232           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                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2709                         document.body[realparbeg : realparbeg] = subst
2710                     elif argnr == "item:2":
2711                         j = find_end_of_inset(document.body, i)
2712                         # Find containing paragraph layout
2713                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2714                         endPlain = find_end_of_layout(document.body, beginPlain)
2715                         content = document.body[beginPlain + 1 : endPlain]
2716                         del document.body[i:j+1]
2717                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2718                         document.body[realparbeg : realparbeg] = subst
2719             if layoutname in quote_layouts:
2720                 m = rx.match(document.body[p])
2721                 if m:
2722                     argnr = m.group(1)
2723                     if argnr == "1":
2724                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2725                         endPlain = find_end_of_layout(document.body, beginPlain)
2726                         endInset = find_end_of_inset(document.body, p)
2727                         content = document.body[beginPlain + 1 : endPlain]
2728                         # Adjust range end
2729                         realparend = realparend - len(document.body[p : endInset + 1])
2730                         # Remove arg inset
2731                         del document.body[p : endInset + 1]
2732                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2733                         document.body[realparbeg : realparbeg] = subst
2734             if layoutname in corollary_layouts:
2735                 m = rx.match(document.body[p])
2736                 if m:
2737                     argnr = m.group(1)
2738                     if argnr == "2":
2739                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2740                         endPlain = find_end_of_layout(document.body, beginPlain)
2741                         endInset = find_end_of_inset(document.body, p)
2742                         content = document.body[beginPlain + 1 : endPlain]
2743                         # Adjust range end
2744                         realparend = realparend - len(document.body[p : endInset + 1])
2745                         # Remove arg inset
2746                         del document.body[p : endInset + 1]
2747                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2748                         document.body[realparbeg : realparbeg] = subst
2749         
2750         i = realparend
2751
2752
2753 def revert_beamerargs2(document):
2754     " Reverts beamer arguments to old layout, step 2 "
2755     
2756     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2757     if document.textclass not in beamer_classes:
2758         return
2759
2760     i = 0
2761     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2762     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2763     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2764
2765     while True:
2766         i = find_token(document.body, "\\begin_inset Argument", i)
2767         if i == -1:
2768             return
2769         # Find containing paragraph layout
2770         parent = get_containing_layout(document.body, i)
2771         if parent == False:
2772             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2773             i += 1
2774             continue
2775         parbeg = parent[1]
2776         parend = parent[2]
2777         realparbeg = parent[3]
2778         layoutname = parent[0]
2779         realparend = parend
2780         for p in range(parbeg, parend):
2781             if p >= realparend:
2782                 i = realparend
2783                 break
2784             if layoutname in shifted_layouts:
2785                 m = rx.match(document.body[p])
2786                 if m:
2787                     argnr = m.group(1)
2788                     if argnr == "2":
2789                         document.body[p] = "\\begin_inset Argument 1"       
2790             if layoutname in corollary_layouts:
2791                 m = rx.match(document.body[p])
2792                 if m:
2793                     argnr = m.group(1)
2794                     if argnr == "1":
2795                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2796                         endPlain = find_end_of_layout(document.body, beginPlain)
2797                         endInset = find_end_of_inset(document.body, p)
2798                         content = document.body[beginPlain + 1 : endPlain]
2799                         # Adjust range end
2800                         realparend = realparend - len(document.body[p : endInset + 1])
2801                         # Remove arg inset
2802                         del document.body[p : endInset + 1]
2803                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2804                         document.body[realparbeg : realparbeg] = subst
2805             if layoutname == "OverlayArea":
2806                 m = rx.match(document.body[p])
2807                 if m:
2808                     argnr = m.group(1)
2809                     if argnr == "1":
2810                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2811                         endPlain = find_end_of_layout(document.body, beginPlain)
2812                         endInset = find_end_of_inset(document.body, p)
2813                         content = document.body[beginPlain + 1 : endPlain]
2814                         # Adjust range end
2815                         realparend = realparend - len(document.body[p : endInset + 1])
2816                         # Remove arg inset
2817                         del document.body[p : endInset + 1]
2818                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2819                         document.body[realparbeg : realparbeg] = subst
2820             if layoutname == "AgainFrame":
2821                 m = rx.match(document.body[p])
2822                 if m:
2823                     argnr = m.group(1)
2824                     if argnr == "2":
2825                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2826                         endPlain = find_end_of_layout(document.body, beginPlain)
2827                         endInset = find_end_of_inset(document.body, p)
2828                         content = document.body[beginPlain + 1 : endPlain]
2829                         # Adjust range end
2830                         realparend = realparend - len(document.body[p : endInset + 1])
2831                         # Remove arg inset
2832                         del document.body[p : endInset + 1]
2833                         subst = put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
2834                         document.body[realparbeg : realparbeg] = subst
2835         i = realparend
2836
2837
2838 def revert_beamerargs3(document):
2839     " Reverts beamer arguments to old layout, step 3 "
2840     
2841     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2842     if document.textclass not in beamer_classes:
2843         return
2844
2845     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2846     i = 0
2847     while True:
2848         i = find_token(document.body, "\\begin_inset Argument", i)
2849         if i == -1:
2850             return
2851         # Find containing paragraph layout
2852         parent = get_containing_layout(document.body, i)
2853         if parent == False:
2854             document.warning("Malformed LyX document: Can't find parent paragraph layout")
2855             i += 1
2856             continue
2857         parbeg = parent[1]
2858         parend = parent[2]
2859         realparbeg = parent[3]
2860         layoutname = parent[0]
2861         realparend = parend
2862         for p in range(parbeg, parend):
2863             if p >= realparend:
2864                 i = realparend
2865                 break
2866             if layoutname == "AgainFrame":
2867                 m = rx.match(document.body[p])
2868                 if m:
2869                     argnr = m.group(1)
2870                     if argnr == "1":
2871                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2872                         endPlain = find_end_of_layout(document.body, beginPlain)
2873                         endInset = find_end_of_inset(document.body, p)
2874                         content = document.body[beginPlain + 1 : endPlain]
2875                         # Adjust range end
2876                         realparend = realparend - len(document.body[p : endInset + 1])
2877                         # Remove arg inset
2878                         del document.body[p : endInset + 1]
2879                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2880                         document.body[realparbeg : realparbeg] = subst
2881         i = realparend
2882
2883
2884 def revert_beamerflex(document):
2885     " Reverts beamer Flex insets "
2886     
2887     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2888     if document.textclass not in beamer_classes:
2889         return
2890
2891     new_flexes = {"Bold" : "\\textbf", "Emphasize" : "\\emph", "Only" : "\\only",
2892                   "Uncover" : "\\uncover", "Visible" : "\\visible",
2893                   "Invisible" : "\\invisible", "Alternative" : "\\alt",
2894                   "Beamer_Note" : "\\note"}
2895     old_flexes = {"Alert" : "\\alert", "Structure" : "\\structure"}
2896     rx = re.compile(r'^\\begin_inset Flex (.+)$')
2897
2898     i = 0
2899     while True:
2900         i = find_token(document.body, "\\begin_inset Flex", i)
2901         if i == -1:
2902             return
2903         m = rx.match(document.body[i])
2904         if m:
2905             flextype = m.group(1)
2906             z = find_end_of_inset(document.body, i)
2907             if z == -1:
2908                 document.warning("Can't find end of Flex " + flextype + " inset.")
2909                 i += 1
2910                 continue
2911             if flextype in new_flexes:
2912                 pre = put_cmd_in_ert(new_flexes[flextype])
2913                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2914                 if arg != -1:
2915                     argend = find_end_of_inset(document.body, arg)
2916                     if argend == -1:
2917                         document.warning("Can't find end of Argument!")
2918                         i += 1
2919                         continue
2920                     # Find containing paragraph layout
2921                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2922                     endPlain = find_end_of_layout(document.body, beginPlain)
2923                     argcontent = document.body[beginPlain + 1 : endPlain]
2924                     # Adjust range end
2925                     z = z - len(document.body[arg : argend + 1])
2926                     # Remove arg inset
2927                     del document.body[arg : argend + 1]
2928                     pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2929                 arg = find_token(document.body, "\\begin_inset Argument 2", i, z)
2930                 if arg != -1:
2931                     argend = find_end_of_inset(document.body, arg)
2932                     if argend == -1:
2933                         document.warning("Can't find end of Argument!")
2934                         i += 1
2935                         continue
2936                     # Find containing paragraph layout
2937                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2938                     endPlain = find_end_of_layout(document.body, beginPlain)
2939                     argcontent = document.body[beginPlain + 1 : endPlain]
2940                     # Adjust range end
2941                     z = z - len(document.body[arg : argend + 1])
2942                     # Remove arg inset
2943                     del document.body[arg : argend + 1]
2944                     if flextype == "Alternative":
2945                         pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
2946                     else:
2947                         pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2948                 pre += put_cmd_in_ert("{")
2949                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2950                 endPlain = find_end_of_layout(document.body, beginPlain)
2951                 # Adjust range end
2952                 z = z - len(document.body[i : beginPlain + 1])
2953                 z += len(pre)
2954                 document.body[i : beginPlain + 1] = pre
2955                 post = put_cmd_in_ert("}")
2956                 document.body[z - 2 : z + 1] = post
2957             elif flextype in old_flexes:
2958                 pre = put_cmd_in_ert(old_flexes[flextype])
2959                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2960                 if arg == -1:
2961                     i += 1
2962                     continue
2963                 argend = find_end_of_inset(document.body, arg)
2964                 if argend == -1:
2965                     document.warning("Can't find end of Argument!")
2966                     i += 1
2967                     continue
2968                 # Find containing paragraph layout
2969                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2970                 endPlain = find_end_of_layout(document.body, beginPlain)
2971                 argcontent = document.body[beginPlain + 1 : endPlain]
2972                 # Adjust range end
2973                 z = z - len(document.body[arg : argend + 1])
2974                 # Remove arg inset
2975                 del document.body[arg : argend + 1]
2976                 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2977                 pre += put_cmd_in_ert("{")
2978                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2979                 endPlain = find_end_of_layout(document.body, beginPlain)
2980                 # Adjust range end
2981                 z = z - len(document.body[i : beginPlain + 1])
2982                 z += len(pre)
2983                 document.body[i : beginPlain + 1] = pre
2984                 post = put_cmd_in_ert("}")
2985                 document.body[z - 2 : z + 1] = post
2986         
2987         i += 1
2988
2989
2990 def revert_beamerblocks(document):
2991     " Reverts beamer block arguments to ERT "
2992     
2993     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2994     if document.textclass not in beamer_classes:
2995         return
2996
2997     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2998
2999     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3000     i = 0
3001     while True:
3002         i = find_token(document.body, "\\begin_inset Argument", i)
3003         if i == -1:
3004             return
3005         # Find containing paragraph layout
3006         parent = get_containing_layout(document.body, i)
3007         if parent == False:
3008             document.warning("Malformed LyX document: Can't find parent paragraph layout")
3009             i += 1
3010             continue
3011         parbeg = parent[1]
3012         parend = parent[2]
3013         realparbeg = parent[3]
3014         layoutname = parent[0]
3015         realparend = parend
3016         for p in range(parbeg, parend):
3017             if p >= realparend:
3018                 i = realparend
3019                 break
3020             if layoutname in blocks:
3021                 m = rx.match(document.body[p])
3022                 if m:
3023                     argnr = m.group(1)
3024                     if argnr == "1":
3025                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3026                         endPlain = find_end_of_layout(document.body, beginPlain)
3027                         endInset = find_end_of_inset(document.body, p)
3028                         content = document.body[beginPlain + 1 : endPlain]
3029                         # Adjust range end
3030                         realparend = realparend - len(document.body[p : endInset + 1])
3031                         # Remove arg inset
3032                         del document.body[p : endInset + 1]
3033                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3034                         document.body[realparbeg : realparbeg] = subst
3035                     elif argnr == "2":
3036                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3037                         endPlain = find_end_of_layout(document.body, beginPlain)
3038                         endInset = find_end_of_inset(document.body, p)
3039                         content = document.body[beginPlain + 1 : endPlain]
3040                         # Adjust range end
3041                         realparend = realparend - len(document.body[p : endInset + 1])
3042                         # Remove arg inset
3043                         del document.body[p : endInset + 1]
3044                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3045                         document.body[realparbeg : realparbeg] = subst
3046         i = realparend
3047
3048
3049
3050 def convert_beamerblocks(document):
3051     " Converts beamer block ERT args to native InsetArgs "
3052     
3053     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3054     if document.textclass not in beamer_classes:
3055         return
3056    
3057     blocks = ["Block", "ExampleBlock", "AlertBlock"]
3058     for lay in blocks:
3059         i = 0
3060         while True:
3061             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
3062             if i == -1:
3063                 break
3064             parent = get_containing_layout(document.body, i)
3065             if parent == False or parent[1] != i:
3066                 document.warning("Wrong parent layout!")
3067                 i += 1
3068                 continue
3069             parbeg = parent[3]
3070             parend = parent[2]
3071             j = parend
3072             if i != -1:
3073                 if document.body[parbeg] == "\\begin_inset ERT":
3074                     ertcontfirstline = parbeg + 5
3075                     lastertbeg = -1
3076                     lastertend = -1
3077                     while True:
3078                         # Find the last ERT in this paragraph used for arguments
3079                         # (which might also be the first)
3080                         lastertbeg = find_token_backwards(document.body, "\\begin_inset ERT", j)
3081                         if lastertbeg == -1:
3082                             document.warning("Last ERT not found!")
3083                             break
3084                         lastertend = find_end_of_inset(document.body, lastertbeg)
3085                         if lastertend == -1:
3086                             document.warning("End of last ERT not found!")
3087                             break
3088                         # Is this ERT really used for an argument?
3089                         # Note: This will fail when non-argument ERTs actually use brackets
3090                         #       (e.g. \pause{})
3091                         regexp = re.compile(r'.*[>\]\}]', re.IGNORECASE)
3092                         cbracket = find_re(document.body, regexp, lastertbeg, lastertend)
3093                         if cbracket != -1:
3094                             break
3095                         if lastertbeg == parbeg:
3096                             break
3097                         j = lastertbeg - 1
3098                     if lastertbeg == -1 or lastertend == -1:
3099                         break
3100                     ertcontlastline = lastertend - 3
3101                     while True:
3102                         if document.body[ertcontfirstline].lstrip().startswith("<"):
3103                             # This is an overlay specification
3104                             # strip off the <
3105                             document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3106                             if document.body[ertcontlastline].rstrip().endswith(">"):
3107                                 # strip off the >
3108                                 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3109                                 # Convert to ArgInset
3110                                 document.body[parbeg] = "\\begin_inset Argument 1"
3111                             elif document.body[ertcontlastline].rstrip().endswith("}"):
3112                                 # strip off the }
3113                                 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3114                                 # divide the args
3115                                 ertcontdivline = ertcontfirstline
3116                                 tok = document.body[ertcontdivline].find('>{')
3117                                 if tok == -1:
3118                                     regexp = re.compile(r'.*>\{', re.IGNORECASE)
3119                                     ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3120                                     tok = document.body[ertcontdivline].find('>{')
3121                                 if tok != -1:
3122                                     if ertcontfirstline < ertcontlastline:
3123                                         # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3124                                         document.body[ertcontlastline : ertcontlastline + 1] = [
3125                                                                             document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3126                                         if ertcontdivline == ertcontfirstline:
3127                                             document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3128                                                                                 '\\end_layout', '', '\\end_inset', '',
3129                                                                                 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3130                                                                                 'status collapsed', '', '\\begin_layout Plain Layout',
3131                                                                                 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3132                                                                                 document.body[ertcontdivline][tok + 2:]]
3133                                         else:
3134                                             document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3135                                                                                 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3136                                                                                 'status collapsed', '', '\\begin_layout Plain Layout',
3137                                                                                 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3138                                                                                 document.body[ertcontdivline][tok + 2:]]
3139                                     else:
3140                                         document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3141                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3142                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3143                                                                             document.body[ertcontdivline][tok + 2:]]
3144                                 else:
3145                                     # check if have delimiters in two different ERTs
3146                                     tok = document.body[ertcontdivline].find('>')
3147                                     if tok == -1:
3148                                         regexp = re.compile(r'.*>', re.IGNORECASE)
3149                                         ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3150                                         tok = document.body[ertcontdivline].find('>')
3151                                     if tok != -1:
3152                                         tokk = document.body[ertcontdivline].find('{')
3153                                         if tokk == -1:
3154                                             regexp = re.compile(r'.*\{', re.IGNORECASE)
3155                                             ertcontdivlinetwo = find_re(document.body, regexp, ertcontfirstline, lastertend)
3156                                             tokk = document.body[ertcontdivlinetwo].find('{')
3157                                         if tokk != -1:
3158                                             if ertcontfirstline < ertcontlastline:
3159                                                 # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3160                                                 document.body[ertcontlastline : ertcontlastline + 1] = [
3161                                                                                     document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3162                                                 document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3163                                                                                     '\\end_layout', '', '\\end_inset', '', '\\end_layout', '', 
3164                                                                                     '\\end_inset', '', '', '\\begin_inset Argument 2',
3165                                                                                     'status collapsed', '', '\\begin_layout Plain Layout',
3166                                                                                     '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3167                                                                                     document.body[ertcontdivlinetwo][tokk + 1:]]
3168                                             else:
3169                                                 document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3170                                                                                     '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3171                                                                                     'status collapsed', '', '\\begin_layout Plain Layout',
3172                                                                                     document.body[ertcontdivlinetwo][tokk + 1:]]
3173                                 # Convert to ArgInset
3174                                 if ertcontfirstline < ertcontlastline:
3175                                     # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3176                                     document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 1',
3177                                                                         'status collapsed', '', '\\begin_layout Plain Layout',
3178                                                                         '\\begin_inset ERT', '']
3179                                 else:
3180                                     document.body[parbeg] = "\\begin_inset Argument 1"
3181                         elif document.body[ertcontfirstline].lstrip().startswith("{"):
3182                             # This is the block title
3183                             if document.body[ertcontlastline].rstrip().endswith("}"):
3184                                 # strip off the braces
3185                                 document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3186                                 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3187                                 if ertcontfirstline < ertcontlastline:
3188                                     # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3189                                     document.body[parend : parend + 1] = [
3190                                                                         document.body[parend], '\\end_inset', '', '\\end_layout']
3191                                     document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 2',
3192                                                                         'status collapsed', '', '\\begin_layout Plain Layout',
3193                                                                         '\\begin_inset ERT', '']
3194                                 else:
3195                                     # Convert to ArgInset
3196                                     document.body[parbeg] = "\\begin_inset Argument 2"
3197                             # the overlay argument can also follow the title, so ...
3198                             elif document.body[ertcontlastline].rstrip().endswith(">"):
3199                                 # strip off the {
3200                                 document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3201                                 # strip off the >
3202                                 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3203                                 # divide the args
3204                                 ertcontdivline = ertcontfirstline
3205                                 tok = document.body[ertcontdivline].find('}<')
3206                                 if tok == -1:
3207                                     regexp = re.compile(r'.*\}<', re.IGNORECASE)
3208                                     ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3209                                     tok = document.body[ertcontdivline].find('}<')
3210                                 if tok != -1:
3211                                     if ertcontfirstline < ertcontlastline:
3212                                         # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3213                                         document.body[ertcontlastline : ertcontlastline + 1] = [
3214                                                                             document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3215                                         document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3216                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3217                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3218                                                                             '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3219                                                                             document.body[ertcontdivline][tok + 2:]]
3220                                     else:
3221                                         document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3222                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3223                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3224                                                                             document.body[ertcontdivline][tok + 2:]]
3225                                 else:
3226                                     # check if have delimiters in two different ERTs
3227                                     tok = document.body[ertcontdivline].find('}')
3228                                     if tok == -1:
3229                                         regexp = re.compile(r'.*\}', re.IGNORECASE)
3230                                         ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3231                                         tok = document.body[ertcontdivline].find('}')
3232                                         if tok != -1:
3233                                             tokk = document.body[ertcontdivline].find('<')
3234                                             if tokk == -1:
3235                                                 regexp = re.compile(r'.*<', re.IGNORECASE)
3236                                                 ertcontdivlinetwo = find_re(document.body, regexp, ertcontfirstline, lastertend)
3237                                                 tokk = document.body[ertcontdivlinetwo].find('<')
3238                                                 if tokk != -1:
3239                                                     if ertcontfirstline < ertcontlastline:
3240                                                         # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3241                                                         document.body[ertcontlastline : ertcontlastline + 1] = [
3242                                                                                             document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3243                                                         document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3244                                                                                             '\\end_layout', '', '\\end_inset', '', '\\end_layout', '', 
3245                                                                                             '\\end_inset', '', '', '\\begin_inset Argument 1',
3246                                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3247                                                                                             '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3248                                                                                             document.body[ertcontdivlinetwo][tokk + 1:]]
3249                                                     else:
3250                                                         document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3251                                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3252                                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
3253                                                                                             document.body[ertcontdivlinetwo][tokk + 1:]]
3254                                 # Convert to ArgInset
3255                                 if ertcontfirstline < ertcontlastline:
3256                                     # Multiline ERT. Might contain TeX code.  Embrace in ERT.
3257                                     document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 2',
3258                                                                         'status collapsed', '', '\\begin_layout Plain Layout',
3259                                                                         '\\begin_inset ERT', '']
3260                                 else:
3261                                     document.body[parbeg] = "\\begin_inset Argument 2"
3262                             elif count_pars_in_inset(document.body, ertcontfirstline) > 1:
3263                                 # Multipar ERT. Skip this.
3264                                 break
3265                             else:
3266                                 # ERT has contents after the closing bracket. We cannot convert this.
3267                                 # convert_TeX_brace_to_Argument cannot either.
3268                                 #convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, False)
3269                                 break
3270                         else:
3271                             break
3272                         j = find_end_of_layout(document.body, i)
3273                         if j == -1:
3274                             document.warning("end of layout not found!")
3275                         k = find_token(document.body, "\\begin_inset Argument", i, j)
3276                         if k == -1:
3277                             document.warning("InsetArgument not found!")
3278                             break
3279                         l = find_end_of_inset(document.body, k)
3280                         m = find_token(document.body, "\\begin_inset ERT", l, j)
3281                         if m == -1:
3282                             break
3283                         ertcontfirstline = m + 5
3284                         parbeg = m
3285             i = j
3286
3287
3288 def convert_overprint(document):
3289     " Convert old beamer overprint layouts to ERT "
3290     
3291     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3292     if document.textclass not in beamer_classes:
3293         return
3294
3295     i = 0
3296     while True:
3297         i = find_token(document.body, "\\begin_layout Overprint", i)
3298         if i == -1:
3299             return
3300         # Find end of sequence
3301         j = find_end_of_sequence(document.body, i)
3302         if j == -1:
3303             document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
3304             i += 1
3305             continue
3306         endseq = j
3307         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
3308         esubst = list()
3309         if document.body[j] == "\\end_deeper":
3310             esubst = ["", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
3311         else:
3312             esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
3313         endseq = endseq + len(esubst) - len(document.body[j : j])
3314         document.body[j : j] = esubst
3315         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3316         if argbeg != -1:
3317             argend = find_end_of_layout(document.body, argbeg)
3318             if argend == -1:
3319                 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3320                 i += 1
3321                 continue
3322             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3323             endPlain = find_end_of_layout(document.body, beginPlain)
3324             content = document.body[beginPlain + 1 : endPlain]
3325             # Adjust range end
3326             endseq = endseq - len(document.body[argbeg : argend + 1])
3327             # Remove arg inset
3328             del document.body[argbeg : argend + 1]
3329             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3330             
3331         endseq = endseq - len(document.body[i : i])
3332         document.body[i : i] = subst + ["\\end_layout"]
3333         endseq += len(subst)
3334         
3335         for p in range(i, endseq):
3336             if document.body[p] == "\\begin_layout Overprint":
3337                 document.body[p] = "\\begin_layout Standard"
3338
3339         i = endseq
3340
3341
3342 def revert_overprint(document):
3343     " Revert old beamer overprint layouts to ERT "
3344     
3345     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3346     if document.textclass not in beamer_classes:
3347         return
3348
3349     i = 0
3350     while True:
3351         i = find_token(document.body, "\\begin_layout Overprint", i)
3352         if i == -1:
3353             return
3354         # Find end of sequence
3355         j = find_end_of_sequence(document.body, i)
3356         if j == -1:
3357             document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
3358             i += 1
3359             continue
3360         endseq = j
3361         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
3362         esubst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}")
3363         endseq = endseq + len(esubst) - len(document.body[j : j])
3364         if document.body[j] == "\\end_deeper":
3365             document.body[j : j] = [""] + esubst + ["", "\\end_layout"]
3366         else:
3367             document.body[j : j] = ["\\end_layout", ""] + esubst
3368         r = i
3369         while r < j:
3370             if document.body[r] == "\\begin_deeper":
3371                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3372                 if s != -1:
3373                     document.body[r] = ""
3374                     document.body[s] = ""
3375                     r = s
3376                     continue
3377             r = r + 1
3378         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3379         if argbeg != -1:
3380             # Is this really our argument?
3381             nested = find_token(document.body, "\\begin_deeper", i, argbeg)
3382             if nested != -1:
3383                 argend = find_end_of_inset(document.body, argbeg)
3384                 if argend == -1:
3385                     document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3386                     i += 1
3387                     continue
3388                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3389                 endPlain = find_end_of_layout(document.body, beginPlain)
3390                 content = document.body[beginPlain + 1 : endPlain]
3391                 # Adjust range end
3392                 endseq = endseq - len(document.body[argbeg : argend])
3393                 # Remove arg inset
3394                 del document.body[argbeg : argend + 1]
3395                 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3396             
3397         endseq = endseq - len(document.body[i : i])
3398         document.body[i : i] = subst + ["\\end_layout"]
3399         endseq += len(subst)
3400      
3401         p = i
3402         while True:
3403             if p >= endseq:
3404                 break
3405             if document.body[p] == "\\begin_layout Overprint":
3406                 q = find_end_of_layout(document.body, p)
3407                 if q == -1:
3408                     document.warning("Malformed LyX document. Cannot find end of Overprint layout!")
3409                     p += 1
3410                     continue
3411                 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\onslide")
3412                 argbeg = find_token(document.body, "\\begin_inset Argument item:1", p, q)
3413                 if argbeg != -1:
3414                     argend = find_end_of_inset(document.body, argbeg)
3415                     if argend == -1:
3416                         document.warning("Malformed LyX document. Cannot find end of Overprint item argument!")
3417                         p += 1
3418                         continue
3419                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3420                     endPlain = find_end_of_layout(document.body, beginPlain)
3421                     content = document.body[beginPlain + 1 : endPlain]
3422                     # Adjust range end
3423                     endseq = endseq - len(document.body[argbeg : argend + 1])
3424                     # Remove arg inset
3425                     del document.body[argbeg : argend + 1]
3426                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3427                 endseq = endseq - len(document.body[p : p + 1]) + len(subst)
3428                 document.body[p : p + 1] = subst
3429             p = p + 1
3430
3431         i = endseq
3432
3433
3434 def revert_frametitle(document):
3435     " Reverts beamer frametitle layout to ERT "
3436     
3437     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3438     if document.textclass not in beamer_classes:
3439         return
3440
3441     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3442     i = 0
3443     while True:
3444         i = find_token(document.body, "\\begin_layout FrameTitle", i)
3445         if i == -1:
3446             return
3447         j = find_end_of_layout(document.body, i)
3448         if j == -1:
3449             document.warning("Malformed LyX document: Can't find end of FrameTitle layout")
3450             i += 1
3451             continue
3452         endlay = j
3453         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
3454         endlay += len(put_cmd_in_ert("}"))
3455         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\frametitle")
3456         for p in range(i, j):
3457             if p >= endlay:
3458                 break
3459             m = rx.match(document.body[p])
3460             if m:
3461                 argnr = m.group(1)
3462                 if argnr == "1":
3463                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3464                     endPlain = find_end_of_layout(document.body, beginPlain)
3465                     endInset = find_end_of_inset(document.body, p)
3466                     content = document.body[beginPlain + 1 : endPlain]
3467                     # Adjust range end
3468                     endlay = endlay - len(document.body[p : endInset + 1])
3469                     # Remove arg inset
3470                     del document.body[p : endInset + 1]
3471                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3472                 elif argnr == "2":
3473                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3474                     endPlain = find_end_of_layout(document.body, beginPlain)
3475                     endInset = find_end_of_inset(document.body, p)
3476                     content = document.body[beginPlain + 1 : endPlain]
3477                     # Adjust range end
3478                     endlay = endlay - len(document.body[p : endInset + 1])
3479                     # Remove arg inset
3480                     del document.body[p : endInset + 1]
3481                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3482                     
3483         subst += put_cmd_in_ert("{")
3484         document.body[i : i + 1] = subst
3485         i = endlay
3486
3487
3488 def convert_epigraph(document):
3489     " Converts memoir epigraph to new syntax "
3490     
3491     if document.textclass != "memoir":
3492         return
3493
3494     i = 0
3495     while True:
3496         i = find_token(document.body, "\\begin_layout Epigraph", i)
3497         if i == -1:
3498             return
3499         j = find_end_of_layout(document.body, i)
3500         if j == -1:
3501             document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3502             i += 1
3503             continue
3504         endlay = j
3505         subst = list()
3506         ert = find_token(document.body, "\\begin_inset ERT", i, j)
3507         if ert != -1:
3508             endInset = find_end_of_inset(document.body, ert)
3509             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", ert)
3510             endPlain = find_end_of_layout(document.body, beginPlain)
3511             ertcont = beginPlain + 2
3512             if document.body[ertcont] == "}{":
3513                 # strip off the <
3514                 # Convert to ArgInset
3515                 endlay = endlay - 2 * len(document.body[j])
3516                 begsubst = ['\\begin_inset Argument post:1', 'status collapsed', '',
3517                             '\\begin_layout Plain Layout']
3518                 endsubst = ['\\end_layout', '', '\\end_inset', '', document.body[j]]
3519                 document.body[j : j + 1] = endsubst
3520                 document.body[endInset + 1 : endInset + 1] = begsubst
3521                 # Adjust range end
3522                 endlay += len(begsubst) + len(endsubst)
3523                 endlay = endlay - len(document.body[ert : endInset + 1])
3524                 del document.body[ert : endInset + 1]
3525                     
3526         i = endlay
3527
3528
3529 def revert_epigraph(document):
3530     " Reverts memoir epigraph argument to ERT "
3531     
3532     if document.textclass != "memoir":
3533         return
3534
3535     i = 0
3536     while True:
3537         i = find_token(document.body, "\\begin_layout Epigraph", i)
3538         if i == -1:
3539             return
3540         j = find_end_of_layout(document.body, i)
3541         if j == -1:
3542             document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3543             i += 1
3544             continue
3545         endlay = j
3546         subst = list()
3547         p = find_token(document.body, "\\begin_layout Argument post:1", i, j)
3548         if p != -1:
3549             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3550             endPlain = find_end_of_layout(document.body, beginPlain)
3551             endInset = find_end_of_inset(document.body, p)
3552             content = document.body[beginPlain + 1 : endPlain]
3553             # Adjust range end
3554             endlay = endlay - len(document.body[p : endInset + 1])
3555             # Remove arg inset
3556             del document.body[p : endInset + 1]
3557             subst += put_cmd_in_ert("}{") + content
3558         else:
3559             subst += put_cmd_in_ert("}{")
3560                     
3561         document.body[j : j] = subst + document.body[j : j]
3562         i = endlay
3563
3564
3565 def convert_captioninsets(document):
3566     " Converts caption insets to new syntax "
3567     
3568     i = 0
3569     while True:
3570       i = find_token(document.body, "\\begin_inset Caption", i)
3571       if i == -1:
3572           return
3573       document.body[i] = "\\begin_inset Caption Standard"
3574       i += 1
3575
3576
3577 def revert_captioninsets(document):
3578     " Reverts caption insets to old syntax "
3579     
3580     i = 0
3581     while True:
3582       i = find_token(document.body, "\\begin_inset Caption Standard", i)
3583       if i == -1:
3584           return
3585       document.body[i] = "\\begin_inset Caption"
3586       i += 1
3587
3588
3589 def convert_captionlayouts(document):
3590     " Convert caption layouts to caption insets. "
3591
3592     caption_dict = {
3593         "Captionabove":  "Above",
3594         "Captionbelow":  "Below",
3595         "FigCaption"  :  "FigCaption",
3596         "Table_Caption" :  "Table",
3597         "CenteredCaption" : "Centered",
3598         "Bicaption" : "Bicaption",
3599         }
3600
3601     i = 0
3602     while True:
3603         i = find_token(document.body, "\\begin_layout", i)
3604         if i == -1:
3605             return
3606         val = get_value(document.body, "\\begin_layout", i)
3607         if val in caption_dict.keys():
3608             j = find_end_of_layout(document.body, i)
3609             if j == -1:
3610                 document.warning("Malformed LyX document: Missing `\\end_layout'.")
3611                 return
3612
3613             document.body[j:j] = ["\\end_layout", "", "\\end_inset", "", ""]
3614             document.body[i:i+1] = ["\\begin_layout %s" % document.default_layout,
3615                                     "\\begin_inset Caption %s" % caption_dict[val], "",
3616                                     "\\begin_layout %s" % document.default_layout]
3617         i += 1
3618
3619
3620 def revert_captionlayouts(document):
3621     " Revert caption insets to caption layouts. "
3622     
3623     caption_dict = {
3624         "Above" : "Captionabove",
3625         "Below" : "Captionbelow",
3626         "FigCaption"  :  "FigCaption",
3627         "Table" : "Table_Caption",
3628         "Centered" : "CenteredCaption",
3629         "Bicaption" : "Bicaption",
3630         }
3631     
3632     i = 0
3633     rx = re.compile(r'^\\begin_inset Caption (\S+)$')
3634     while True:
3635         i = find_token(document.body, "\\begin_inset Caption", i)
3636         if i == -1:
3637             return
3638
3639         m = rx.match(document.body[i])
3640         val = ""
3641         if m:
3642             val = m.group(1)
3643         if val not in caption_dict.keys():
3644             i += 1
3645             continue
3646         
3647         # We either need to delete the previous \begin_layout line, or we
3648         # need to end the previous layout if this inset is not in the first
3649         # position of the paragraph.
3650         layout_before = find_token_backwards(document.body, "\\begin_layout", i)
3651         if layout_before == -1:
3652             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3653             return
3654         layout_line = document.body[layout_before]
3655         del_layout_before = True
3656         l = layout_before + 1
3657         while l < i:
3658             if document.body[l] != "":
3659                 del_layout_before = False
3660                 break
3661             l = l + 1
3662         if del_layout_before:
3663             del document.body[layout_before:i]
3664             i = layout_before
3665         else:
3666             document.body[i:i] = ["\\end_layout", ""]
3667             i = i + 2
3668
3669         # Find start of layout in the inset and end of inset
3670         j = find_token(document.body, "\\begin_layout", i)
3671         if j == -1:
3672             document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3673             return
3674         k = find_end_of_inset(document.body, i)
3675         if k == -1:
3676             document.warning("Malformed LyX document: Missing `\\end_inset'.")
3677             return
3678
3679         # We either need to delete the following \end_layout line, or we need
3680         # to restart the old layout if this inset is not at the paragraph end.
3681         layout_after = find_token(document.body, "\\end_layout", k)
3682         if layout_after == -1:
3683             document.warning("Malformed LyX document: Missing `\\end_layout'.")
3684             return
3685         del_layout_after = True
3686         l = k + 1
3687         while l < layout_after:
3688             if document.body[l] != "":
3689                 del_layout_after = False
3690                 break
3691             l = l + 1
3692         if del_layout_after:
3693             del document.body[k+1:layout_after+1]
3694         else:
3695             document.body[k+1:k+1] = [layout_line, ""]
3696
3697         # delete \begin_layout and \end_inset and replace \begin_inset with
3698         # "\begin_layout XXX". This works because we can only have one
3699         # paragraph in the caption inset: The old \end_layout will be recycled.
3700         del document.body[k]
3701         if document.body[k] == "":
3702             del document.body[k]
3703         del document.body[j]
3704         if document.body[j] == "":
3705             del document.body[j]
3706         document.body[i] = "\\begin_layout %s" % caption_dict[val]
3707         if document.body[i+1] == "":
3708             del document.body[i+1]
3709         i += 1
3710
3711
3712 def revert_fragileframe(document):
3713     " Reverts beamer FragileFrame layout to ERT "
3714     
3715     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3716     if document.textclass not in beamer_classes:
3717         return
3718
3719     i = 0
3720     while True:
3721         i = find_token(document.body, "\\begin_layout FragileFrame", i)
3722         if i == -1:
3723             return
3724         # Find end of sequence
3725         j = find_end_of_sequence(document.body, i)
3726         if j == -1:
3727             document.warning("Malformed LyX document. Cannot find end of FragileFrame sequence!")
3728             i += 1
3729             continue
3730         endseq = j
3731         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{frame}")
3732         esubst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\end{frame}")
3733         endseq = endseq + len(esubst) - len(document.body[j : j])
3734         if document.body[j] == "\\end_deeper":
3735             document.body[j : j] = [""] + esubst + ["", "\\end_layout"]
3736         else:
3737             document.body[j : j] = esubst
3738         for q in range(i, j):
3739             if document.body[q] == "\\begin_layout FragileFrame":
3740                 document.body[q] = "\\begin_layout %s" % document.default_layout
3741         r = i
3742         while r < j:
3743             if document.body[r] == "\\begin_deeper":
3744                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3745                 if s != -1:
3746                     document.body[r] = ""
3747                     document.body[s] = ""
3748                     r = s
3749                     continue
3750             r = r + 1
3751         for p in range(1, 5):
3752             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, j)
3753             if arg != -1:
3754                 if p == 1:
3755                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3756                     endPlain = find_end_of_layout(document.body, beginPlain)
3757                     endInset = find_end_of_inset(document.body, arg)
3758                     content = document.body[beginPlain + 1 : endPlain]
3759                     # Adjust range end
3760                     j = j - len(document.body[arg : endInset + 1])
3761                     # Remove arg inset
3762                     del document.body[arg : endInset + 1]
3763                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3764                 elif p == 2:
3765                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3766                     endPlain = find_end_of_layout(document.body, beginPlain)
3767                     endInset = find_end_of_inset(document.body, arg)
3768                     content = document.body[beginPlain + 1 : endPlain]
3769                     # Adjust range end
3770                     j = j - len(document.body[arg : endInset + 1])
3771                     # Remove arg inset
3772                     del document.body[arg : endInset + 1]
3773                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3774                 elif p == 3:
3775                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3776                     endPlain = find_end_of_layout(document.body, beginPlain)
3777                     endInset = find_end_of_inset(document.body, arg)
3778                     content = document.body[beginPlain + 1 : endPlain]
3779                     # Adjust range end
3780                     j = j - len(document.body[arg : endInset + 1])
3781                     # Remove arg inset
3782                     del document.body[arg : endInset + 1]
3783                     subst += put_cmd_in_ert("[fragile,") + content + put_cmd_in_ert("]")
3784                 elif p == 4:
3785                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3786                     endPlain = find_end_of_layout(document.body, beginPlain)
3787                     endInset = find_end_of_inset(document.body, arg)
3788                     content = document.body[beginPlain + 1 : endPlain]
3789                     # Adjust range end
3790                     j = j - len(document.body[arg : endInset + 1])
3791                     # Remove arg inset
3792                     del document.body[arg : endInset + 1]
3793                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3794             elif p == 3:
3795                 subst += put_cmd_in_ert("[fragile]")
3796                     
3797         document.body[i : i + 1] = subst
3798         i = j
3799
3800
3801 def revert_newframes(document):
3802     " Reverts beamer Frame and PlainFrame layouts to old forms "
3803     
3804     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3805     if document.textclass not in beamer_classes:
3806         return
3807
3808     frame_dict = {
3809         "Frame" : "BeginFrame",
3810         "PlainFrame" : "BeginPlainFrame",
3811         }
3812
3813     rx = re.compile(r'^\\begin_layout (\S+)$')
3814     i = 0
3815     while True:
3816         i = find_token(document.body, "\\begin_layout", i)
3817         if i == -1:
3818             return
3819
3820         m = rx.match(document.body[i])
3821         val = ""
3822         if m:
3823             val = m.group(1)
3824         if val not in frame_dict.keys():
3825             i += 1
3826             continue
3827         # Find end of sequence
3828         j = find_end_of_sequence(document.body, i)
3829         if j == -1:
3830             document.warning("Malformed LyX document. Cannot find end of Frame sequence!")
3831             i += 1
3832             continue
3833         endseq = j
3834         subst = ["\\begin_layout %s" % frame_dict[val]]
3835         esubst = ["", "\\begin_layout EndFrame", "", "\\end_layout"]
3836         endseq = endseq + len(esubst) - len(document.body[j : j])
3837         if document.body[j] == "\\end_deeper":
3838             document.body[j : j] = esubst
3839         else:
3840             document.body[j+1 : j+1] = esubst
3841         for q in range(i, j):
3842             if document.body[q] == "\\begin_layout %s" % val:
3843                 document.body[q] = "\\begin_layout %s" % document.default_layout
3844         r = i
3845         while r < j:
3846             if document.body[r] == "\\begin_deeper":
3847                 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3848                 if s != -1:
3849                     document.body[r] = ""
3850                     document.body[s] = ""
3851                     r = s
3852                     continue
3853             r = r + 1
3854         l = find_end_of_layout(document.body, i)
3855         for p in range(1, 5):
3856             arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, l)
3857             if arg != -1:
3858                 if p == 1:
3859                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3860                     endPlain = find_end_of_layout(document.body, beginPlain)
3861                     endInset = find_end_of_inset(document.body, arg)
3862                     content = document.body[beginPlain + 1 : endPlain]
3863                     # Adjust range end
3864                     l = l - len(document.body[arg : endInset + 1])
3865                     # Remove arg inset
3866                     del document.body[arg : endInset + 1]
3867                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3868                 elif p == 2:
3869                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3870                     endPlain = find_end_of_layout(document.body, beginPlain)
3871                     endInset = find_end_of_inset(document.body, arg)
3872                     content = document.body[beginPlain + 1 : endPlain]
3873                     # Adjust range end
3874                     l = l - len(document.body[arg : endInset + 1])
3875                     # Remove arg inset
3876                     del document.body[arg : endInset + 1]
3877                     subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3878                 elif p == 3:
3879                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3880                     endPlain = find_end_of_layout(document.body, beginPlain)
3881                     endInset = find_end_of_inset(document.body, arg)
3882                     content = document.body[beginPlain + 1 : endPlain]
3883                     # Adjust range end
3884                     l = l - len(document.body[arg : endInset + 1])
3885                     # Remove arg inset
3886                     del document.body[arg : endInset + 1]
3887                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3888                 elif p == 4:
3889                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3890                     endPlain = find_end_of_layout(document.body, beginPlain)
3891                     endInset = find_end_of_inset(document.body, arg)
3892                     content = document.body[beginPlain + 1 : endPlain]
3893                     # Adjust range end
3894                     l = l - len(document.body[arg : endInset + 1])
3895                     # Remove arg inset
3896                     del document.body[arg : endInset + 1]
3897                     subst += content
3898                     
3899         document.body[i : i + 1] = subst
3900         i = j
3901
3902 # known encodings that do not change their names (same LyX and LaTeX names)
3903 known_enc_tuple = ("auto", "default", "ansinew", "applemac", "armscii8", "ascii",
3904     "cp437", "cp437de", "cp850", "cp852", "cp855", "cp858", "cp862", "cp865", "cp866",
3905     "cp1250", "cp1251", "cp1252", "cp1255", "cp1256", "cp1257", "koi8-r", "koi8-u",
3906     "pt154", "pt254", "tis620-0", "utf8", "utf8x", "utf8-plain")
3907
3908 def convert_encodings(document):
3909     "Use the LyX names of the encodings instead of the LaTeX names."
3910     LaTeX2LyX_enc_dict = {
3911         "8859-6":     "iso8859-6",
3912         "8859-8":     "iso8859-8",
3913         "Bg5":        "big5",
3914         "euc":        "euc-jp-platex",
3915         "EUC-JP":     "euc-jp",
3916         "EUC-TW":     "euc-tw",
3917         "GB":         "euc-cn",
3918         "GBK":        "gbk",
3919         "iso88595":   "iso8859-5",
3920         "iso-8859-7": "iso8859-7",
3921         "JIS":        "jis",
3922         "jis":        "jis-platex",
3923         "KS":         "euc-kr",
3924         "l7xenc":     "iso8859-13",
3925         "latin1":     "iso8859-1",
3926         "latin2":     "iso8859-2",
3927         "latin3":     "iso8859-3",
3928         "latin4":     "iso8859-4",
3929         "latin5":     "iso8859-9",
3930         "latin9":     "iso8859-15",
3931         "latin10":    "iso8859-16",
3932         "SJIS":       "shift-jis",
3933         "sjis":       "shift-jis-platex",
3934         "UTF8":       "utf8-cjk"
3935     }
3936     i = find_token(document.header, "\\inputencoding" , 0)
3937     if i == -1:
3938         return
3939     val = get_value(document.header, "\\inputencoding", i)
3940     if val in LaTeX2LyX_enc_dict.keys():
3941         document.header[i] = "\\inputencoding %s" % LaTeX2LyX_enc_dict[val]
3942     elif val not in known_enc_tuple:
3943         document.warning("Ignoring unknown input encoding: `%s'" % val)
3944
3945
3946 def revert_encodings(document):
3947     """Revert to using the LaTeX names of the encodings instead of the LyX names.
3948     Also revert utf8-platex to sjis, the language default when using Japanese.
3949     """
3950     LyX2LaTeX_enc_dict = {
3951         "big5":             "Bg5",
3952         "euc-cn":           "GB",
3953         "euc-kr":           "KS",
3954         "euc-jp":           "EUC-JP",
3955         "euc-jp-platex":    "euc",
3956         "euc-tw":           "EUC-TW",
3957         "gbk":              "GBK",
3958         "iso8859-1":        "latin1",
3959         "iso8859-2":        "latin2",
3960         "iso8859-3":        "latin3",
3961         "iso8859-4":        "latin4",
3962         "iso8859-5":        "iso88595",
3963         "iso8859-6":        "8859-6",
3964         "iso8859-7":        "iso-8859-7",
3965         "iso8859-8":        "8859-8",
3966         "iso8859-9":        "latin5",
3967         "iso8859-13":       "l7xenc",
3968         "iso8859-15":       "latin9",
3969         "iso8859-16":       "latin10",
3970         "jis":              "JIS",
3971         "jis-platex":       "jis",
3972         "shift-jis":        "SJIS",
3973         "shift-jis-platex": "sjis",
3974         "utf8-cjk":         "UTF8",
3975         "utf8-platex":      "sjis"
3976     }
3977     i = find_token(document.header, "\\inputencoding" , 0)
3978     if i == -1:
3979         return
3980     val = get_value(document.header, "\\inputencoding", i)
3981     if val in LyX2LaTeX_enc_dict.keys():
3982         document.header[i] = "\\inputencoding %s" % LyX2LaTeX_enc_dict[val]
3983     elif val not in known_enc_tuple:
3984         document.warning("Ignoring unknown input encoding: `%s'" % val)
3985
3986
3987 def revert_IEEEtran_3(document):
3988   '''
3989   Reverts Flex Insets to TeX-code
3990   '''
3991   if document.textclass == "IEEEtran":
3992     h = 0
3993     i = 0
3994     j = 0
3995     while True:
3996       if h != -1:
3997         h = find_token(document.body, "\\begin_inset Flex Author Mark", h)
3998       if h != -1:
3999         endh = find_end_of_inset(document.body, h)
4000         document.body[endh - 2 : endh + 1] = put_cmd_in_ert("}")
4001         document.body[h : h + 4] = put_cmd_in_ert("\\IEEEauthorrefmark{")
4002         h = h + 5
4003       if i != -1:
4004         i = find_token(document.body, "\\begin_inset Flex Author Name", i)
4005       if i != -1:
4006         endi = find_end_of_inset(document.body, i)
4007         document.body[endi - 2 : endi + 1] = put_cmd_in_ert("}")
4008         document.body[i : i + 4] = put_cmd_in_ert("\\IEEEauthorblockN{")
4009         i = i + 5
4010       if j != -1:
4011         j = find_token(document.body, "\\begin_inset Flex Author Affiliation", j)
4012       if j != -1:
4013         endj = find_end_of_inset(document.body, j)
4014         document.body[endj - 2 : endj + 1] = put_cmd_in_ert("}")
4015         document.body[j : j + 4] = put_cmd_in_ert("\\IEEEauthorblockA{")
4016         j = j + 5
4017       if i == -1 and j == -1 and h == -1:
4018         return
4019
4020
4021 def revert_kurier_fonts(document):
4022   " Revert kurier font definition to LaTeX "
4023   
4024   i = find_token(document.header, "\\font_math", 0)
4025   if i != -1:
4026     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
4027       val = get_value(document.header, "\\font_math", i)
4028       if val == "kurier-math":
4029         add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
4030           "\\usepackage[math]{kurier}\n" \
4031           "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
4032         document.header[i] = "\\font_math auto"
4033   
4034   if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
4035     kurier_fonts = ["kurier", "kurierc", "kurierl", "kurierlc"]
4036     k = find_token(document.header, "\\font_sans kurier", 0)
4037     if k != -1:
4038       sf = get_value(document.header, "\\font_sans", k)
4039       if sf in kurier_fonts:
4040         add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
4041         document.header[k] = "\\font_sans default"
4042
4043 def revert_iwona_fonts(document):
4044   " Revert iwona font definition to LaTeX "
4045   
4046   i = find_token(document.header, "\\font_math", 0)
4047   if i != -1:
4048     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
4049       val = get_value(document.header, "\\font_math", i)
4050       if val == "iwona-math":
4051         add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
4052           "\\usepackage[math]{iwona}\n" \
4053           "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
4054         document.header[i] = "\\font_math auto"
4055   
4056   if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
4057     iwona_fonts = ["iwona", "iwonac", "iwonal", "iwonalc"]
4058     k = find_token(document.header, "\\font_sans iwona", 0)
4059     if k != -1:
4060       sf = get_value(document.header, "\\font_sans", k)
4061       if sf in iwona_fonts:
4062         add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
4063         document.header[k] = "\\font_sans default"
4064
4065
4066 def revert_new_libertines(document):
4067     " Revert new libertine font definition to LaTeX "
4068   
4069     if find_token(document.header, "\\use_non_tex_fonts true", 0) != -1:
4070         return
4071
4072     i = find_token(document.header, "\\font_typewriter libertine-mono", 0)
4073     if i != -1:
4074         preamble = "\\usepackage"
4075         sc = find_token(document.header, "\\font_tt_scale", 0)
4076         if sc != -1:
4077             scval = get_value(document.header, "\\font_tt_scale", sc)
4078             if scval != "100":
4079                 preamble += "[scale=%f]" % (float(scval) / 100)
4080                 document.header[sc] = "\\font_tt_scale 100"
4081         preamble += "{libertineMono-type1}"
4082         add_to_preamble(document, [preamble])
4083         document.header[i] = "\\font_typewriter default"
4084    
4085     k = find_token(document.header, "\\font_sans biolinum", 0)
4086     if k != -1:
4087         preamble = "\\usepackage"
4088         options = ""
4089         j = find_token(document.header, "\\font_osf true", 0)
4090         if j != -1:
4091             options += "osf"
4092         else:
4093             options += "lining"
4094         sc = find_token(document.header, "\\font_sf_scale", 0)
4095         if sc != -1:
4096             scval = get_value(document.header, "\\font_sf_scale", sc)
4097             if scval != "100":
4098                 options += ",scale=%f" % (float(scval) / 100)
4099                 document.header[sc] = "\\font_sf_scale 100"
4100         if options != "":
4101             preamble += "[" + options +"]"
4102         preamble += "{biolinum-type1}"
4103         add_to_preamble(document, [preamble])
4104         document.header[k] = "\\font_sans default"
4105
4106
4107 def convert_lyxframes(document):
4108     " Converts old beamer frames to new style "
4109     
4110     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
4111     if document.textclass not in beamer_classes:
4112         return
4113    
4114     framebeg = ["BeginFrame", "BeginPlainFrame"]
4115     frameend = ["Frame", "PlainFrame", "EndFrame", "BeginFrame", "BeginPlainFrame", "AgainFrame",
4116                 "Section", "Section*", "Subsection", "Subsection*", "Subsubsection", "Subsubsection*"]
4117     for lay in framebeg:
4118         i = 0
4119         while True:
4120             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
4121             if i == -1:
4122                 break
4123             parent = get_containing_layout(document.body, i)
4124             if parent == False or parent[1] != i:
4125                 document.warning("Wrong parent layout!")
4126                 i += 1
4127                 continue
4128             frametype = parent[0]
4129             j = parent[2]
4130             parbeg = parent[3]
4131             if i != -1:
4132                 # Step I: Convert ERT arguments
4133                 # FIXME: See restrictions in convert_beamerframeargs method
4134                 ertend = convert_beamerframeargs(document, i, parbeg)
4135                 if ertend == -1:
4136                     break
4137                 # Step II: Now rename the layout and convert the title to an argument
4138                 j = find_end_of_layout(document.body, i)
4139                 document.body[j : j + 1] = ['\\end_layout', '', '\\end_inset', '', '\\end_layout']
4140                 if lay == "BeginFrame":
4141                     document.body[i] = "\\begin_layout Frame"
4142                 else:
4143                     document.body[i] = "\\begin_layout PlainFrame"
4144                 document.body[ertend + 1 : ertend + 1] = ['\\begin_inset Argument 4',
4145                                                 'status open', '', '\\begin_layout Plain Layout']
4146                 # Step III: find real frame end
4147                 j = j + 8
4148                 jj = j
4149                 while True:
4150                     fend = find_token(document.body, "\\begin_layout", jj)
4151                     if fend == -1:
4152                         document.warning("Malformed LyX document: No real frame end!")
4153                         return
4154                     val = get_value(document.body, "\\begin_layout", fend)
4155                     if val not in frameend:
4156                         jj = fend + 1
4157                         continue
4158                     old = document.body[fend]
4159                     if val == frametype:
4160                         document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
4161                     # consider explicit EndFrames between two identical frame types
4162                     elif val == "EndFrame":
4163                         nextlayout = find_token(document.body, "\\begin_layout", fend + 1)
4164                         if nextlayout != -1 and get_value(document.body, "\\begin_layout", nextlayout) == frametype:
4165                             document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
4166                         else:
4167                             document.body[fend : fend] = ['\\end_deeper']
4168                     else:
4169                         document.body[fend : fend] = ['\\end_deeper']
4170                     document.body[j + 1 : j + 1] = ['', '\\begin_deeper']
4171                     break
4172             i = j
4173
4174
4175 def remove_endframes(document):
4176     " Remove deprecated beamer endframes "
4177     
4178     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
4179     if document.textclass not in beamer_classes:
4180         return
4181    
4182     i = 0
4183     while True:
4184         i = find_token_exact(document.body, "\\begin_layout EndFrame", i)
4185         if i == -1:
4186             break
4187         j = find_end_of_layout(document.body, i)
4188         if j == -1:
4189             document.warning("Malformed LyX document: Missing \\end_layout to EndFrame")
4190             i += 1
4191             continue
4192         del document.body[i : j + 1]
4193
4194
4195 def revert_powerdot_flexes(document):
4196     " Reverts powerdot flex insets "
4197     
4198     if document.textclass != "powerdot":
4199         return
4200
4201     flexes = {"Onslide" : "\\onslide",
4202               "Onslide*" : "\\onslide*",
4203               "Onslide+" : "\\onslide+"}
4204     rx = re.compile(r'^\\begin_inset Flex (.+)$')
4205
4206     i = 0
4207     while True:
4208         i = find_token(document.body, "\\begin_inset Flex", i)
4209         if i == -1:
4210             return
4211         m = rx.match(document.body[i])
4212         if m:
4213             flextype = m.group(1)
4214             z = find_end_of_inset(document.body, i)
4215             if z == -1:
4216                 document.warning("Can't find end of Flex " + flextype + " inset.")
4217                 i += 1
4218                 continue
4219             if flextype in flexes:
4220                 pre = put_cmd_in_ert(flexes[flextype])
4221                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
4222                 if arg != -1:
4223                     argend = find_end_of_inset(document.body, arg)
4224                     if argend == -1:
4225                         document.warning("Can't find end of Argument!")
4226                         i += 1
4227                         continue
4228                     # Find containing paragraph layout
4229                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
4230                     endPlain = find_end_of_layout(document.body, beginPlain)
4231                     argcontent = document.body[beginPlain + 1 : endPlain]
4232                     # Adjust range end
4233                     z = z - len(document.body[arg : argend + 1])
4234                     # Remove arg inset
4235                     del document.body[arg : argend + 1]
4236                     pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
4237                 pre += put_cmd_in_ert("{")
4238                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4239                 endPlain = find_end_of_layout(document.body, beginPlain)
4240                 # Adjust range end
4241                 z = z - len(document.body[i : beginPlain + 1])
4242                 z += len(pre)
4243                 document.body[i : beginPlain + 1] = pre
4244                 post = put_cmd_in_ert("}")
4245                 document.body[z - 2 : z + 1] = post     
4246         i += 1
4247
4248
4249 def revert_powerdot_pause(document):
4250     " Reverts powerdot pause layout to ERT "
4251     
4252     if document.textclass != "powerdot":
4253         return
4254
4255     i = 0
4256     while True:
4257         i = find_token(document.body, "\\begin_layout Pause", i)
4258         if i == -1:
4259             return
4260         j = find_end_of_layout(document.body, i)
4261         if j == -1:
4262             document.warning("Malformed LyX document: Can't find end of Pause layout")
4263             i += 1
4264             continue
4265         endlay = j
4266         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\pause")
4267         for p in range(i, j):
4268             if p >= endlay:
4269                 break
4270             arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
4271             if arg != -1:
4272                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4273                 endPlain = find_end_of_layout(document.body, beginPlain)
4274                 endInset = find_end_of_inset(document.body, p)
4275                 content = document.body[beginPlain + 1 : endPlain]
4276                 # Adjust range end
4277                 endlay = endlay - len(document.body[p : endInset + 1])
4278                 # Remove arg inset
4279                 del document.body[p : endInset + 1]
4280                 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4281                     
4282         document.body[i : i + 1] = subst
4283         i = endlay
4284
4285
4286 def revert_powerdot_itemargs(document):
4287     " Reverts powerdot item arguments to ERT "
4288     
4289     if document.textclass != "powerdot":
4290         return
4291
4292     i = 0
4293     list_layouts = ["Itemize", "ItemizeType1", "Enumerate", "EnumerateType1"]
4294     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4295
4296     while True:
4297         i = find_token(document.body, "\\begin_inset Argument", i)
4298         if i == -1:
4299             return
4300         # Find containing paragraph layout
4301         parent = get_containing_layout(document.body, i)
4302         if parent == False:
4303             document.warning("Malformed LyX document: Can't find parent paragraph layout")
4304             i += 1
4305             continue
4306         parbeg = parent[1]
4307         parend = parent[2]
4308         realparbeg = parent[3]
4309         layoutname = parent[0]
4310         realparend = parend
4311         for p in range(parbeg, parend):
4312             if p >= realparend:
4313                 i = realparend
4314                 break
4315             if layoutname in list_layouts:
4316                 m = rx.match(document.body[p])
4317                 if m:
4318                     argnr = m.group(1)
4319                     if argnr == "item:1":
4320                         j = find_end_of_inset(document.body, i)
4321                         # Find containing paragraph layout
4322                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4323                         endPlain = find_end_of_layout(document.body, beginPlain)
4324                         content = document.body[beginPlain + 1 : endPlain]
4325                         del document.body[i:j+1]
4326                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4327                         document.body[realparbeg : realparbeg] = subst
4328                     elif argnr == "item:2":
4329                         j = find_end_of_inset(document.body, i)
4330                         # Find containing paragraph layout
4331                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4332                         endPlain = find_end_of_layout(document.body, beginPlain)
4333                         content = document.body[beginPlain + 1 : endPlain]
4334                         del document.body[i:j+1]
4335                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
4336                         document.body[realparbeg : realparbeg] = subst
4337         
4338         i = realparend
4339
4340
4341 def revert_powerdot_columns(document):
4342     " Reverts powerdot twocolumn to TeX-code "
4343     if document.textclass != "powerdot":
4344         return
4345
4346     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4347     i = 0
4348     while True:
4349         i = find_token(document.body, "\\begin_layout Twocolumn", i)
4350         if i == -1:
4351             return
4352         j = find_end_of_layout(document.body, i)
4353         if j == -1:
4354             document.warning("Malformed LyX document: Can't find end of Twocolumn layout")
4355             i += 1
4356             continue
4357         endlay = j
4358         document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
4359         endlay += len(put_cmd_in_ert("}"))
4360         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\twocolumn")
4361         for p in range(i, j):
4362             if p >= endlay:
4363                 break
4364             m = rx.match(document.body[p])
4365             if m:
4366                 argnr = m.group(1)
4367                 if argnr == "1":
4368                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4369                     endPlain = find_end_of_layout(document.body, beginPlain)
4370                     endInset = find_end_of_inset(document.body, p)
4371                     content = document.body[beginPlain + 1 : endPlain]
4372                     # Adjust range end
4373                     endlay = endlay - len(document.body[p : endInset + 1])
4374                     # Remove arg inset
4375                     del document.body[p : endInset + 1]
4376                     subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4377                 elif argnr == "2":
4378                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4379                     endPlain = find_end_of_layout(document.body, beginPlain)
4380                     endInset = find_end_of_inset(document.body, p)
4381                     content = document.body[beginPlain + 1 : endPlain]
4382                     # Adjust range end
4383                     endlay = endlay - len(document.body[p : endInset + 1])
4384                     # Remove arg inset
4385                     del document.body[p : endInset + 1]
4386                     subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
4387                     
4388         subst += put_cmd_in_ert("{")
4389         document.body[i : i + 1] = subst
4390         i = endlay
4391
4392
4393 def revert_mbox_fbox(document):
4394     'Convert revert mbox/fbox boxes to TeX-code'
4395     i = 0
4396     while True:
4397         i = find_token(document.body, "\\begin_inset Box", i)
4398         if i == -1:
4399             return
4400         j = find_token(document.body, "width", i)
4401         if j != i + 7:
4402             document.warning("Malformed LyX document: Can't find box width")
4403             return
4404         width = get_value(document.body, "width", j)
4405         k = find_end_of_inset(document.body, j)
4406         if k == -1:
4407             document.warning("Malformed LyX document: Can't find end of box inset")
4408             i += 1
4409             continue
4410         BeginLayout = find_token(document.body, "\\begin_layout Plain Layout", j)
4411         EndLayout = find_end_of_layout(document.body, BeginLayout)
4412         # replace if width is ""
4413         if (width == '""'):
4414             document.body[EndLayout:k + 1] = put_cmd_in_ert("}")
4415             if document.body[i] == "\\begin_inset Box Frameless":
4416                 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\mbox{")
4417             if document.body[i] == "\\begin_inset Box Boxed":
4418                 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\fbox{")
4419         i += 1
4420
4421
4422 def revert_starred_caption(document):
4423     " Reverts unnumbered longtable caption insets "
4424     
4425     i = 0
4426     while True:
4427       i = find_token(document.body, "\\begin_inset Caption LongTableNoNumber", i)
4428       if i == -1:
4429           return
4430       # This is not equivalent, but since the caption inset is a full blown
4431       # text inset a true conversion to ERT is too difficult.
4432       document.body[i] = "\\begin_inset Caption Standard"
4433       i += 1
4434
4435
4436 def revert_forced_local_layout(document):
4437     i = 0
4438     while True:
4439         i = find_token(document.header, "\\begin_forced_local_layout", i)
4440         if i == -1:
4441             return
4442         j = find_end_of(document.header, i, "\\begin_forced_local_layout", "\\end_forced_local_layout")
4443         if j == -1:
4444             # this should not happen
4445             break
4446         regexp = re.compile(r'\s*forcelocal', re.IGNORECASE)
4447         k = find_re(document.header, regexp, i, j)
4448         while k != -1:
4449             del document.header[k]
4450             j = j - 1
4451             k = find_re(document.header, regexp, i, j)
4452         k = find_token(document.header, "\\begin_local_layout", 0)
4453         if k == -1:
4454             document.header[i] = "\\begin_local_layout"
4455             document.header[j] = "\\end_local_layout"
4456         else:
4457             l = find_end_of(document.header, k, "\\begin_local_layout", "\\end_local_layout")
4458             if j == -1:
4459                 # this should not happen
4460                 break
4461             lines = document.header[i+1 : j]
4462             if k > i:
4463                 document.header[k+1 : k+1] = lines
4464                 document.header[i   : j  ] = []
4465             else:
4466                 document.header[i   : j  ] = []
4467                 document.header[k+1 : k+1] = lines
4468
4469
4470 def revert_aa1(document):
4471   " Reverts InsetArguments of aa to TeX-code "
4472   if document.textclass == "aa":
4473     i = 0
4474     while True:
4475       if i != -1:
4476         i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4477       if i != -1:
4478         revert_Argument_to_TeX_brace(document, i, 0, 1, 4, False, False)
4479         i += 1
4480       if i == -1:
4481         return
4482
4483
4484 def revert_aa2(document):
4485   " Reverts InsetArguments of aa to TeX-code "
4486   if document.textclass == "aa":
4487     i = 0
4488     while True:
4489       if i != -1:
4490         i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4491       if i != -1:
4492         document.body[i] = "\\begin_layout Abstract"
4493         i += 1
4494       if i == -1:
4495         return
4496
4497
4498 def revert_tibetan(document):
4499     "Set the document language for Tibetan to English" 
4500
4501     if document.language == "tibetan":
4502         document.language = "english"
4503         i = find_token(document.header, "\\language", 0) 
4504         if i != -1: 
4505             document.header[i] = "\\language english" 
4506     j = 0
4507     while j < len(document.body): 
4508         j = find_token(document.body, "\\lang tibetan", j)
4509         if j != -1:
4510             document.body[j] = document.body[j].replace("\\lang tibetan", "\\lang english")
4511             j += 1
4512         else:
4513             j = len(document.body)
4514
4515
4516 #############
4517 #
4518 # Chunk stuff
4519 #
4520 #############
4521
4522 # The idea here is that we will have a sequence of chunk paragraphs.
4523 # We want to convert them to paragraphs in one or several chunk insets.
4524 # Individual chunks are terminated by the character @ on the last line.
4525 # This line will be discarded, and following lines are treated as new
4526 # chunks, which go into their own insets.
4527 # The first line of a chunk should look like: <<CONTENT>>=
4528 # We will discard the delimiters, and put the CONTENT into the
4529 # optional argument of the inset, if the CONTENT is non-empty.
4530 def convert_chunks(document):
4531     first_re = re.compile(r'<<(.*)>>=(.*)')
4532     file_pos = 0
4533     while True:
4534         # find start of a block of chunks
4535         i = find_token(document.body, "\\begin_layout Chunk", file_pos)
4536         if i == -1:
4537             return
4538         start = i
4539         end = -1
4540         contents = []
4541         chunk_started = False
4542
4543         while True:
4544             # process the one we just found
4545             j = find_end_of_layout(document.body, i)
4546             if j == -1:
4547                 document.warning("Malformed LyX documents. Can't find end of Chunk layout!")
4548                 # there is no point continuing, as we will run into the same error again.
4549                 return
4550             this_chunk = "".join(document.body[i + 1:j])
4551             
4552             # there may be empty lines between chunks
4553             # we just skip them.
4554             if not chunk_started:
4555                 if this_chunk != "":
4556                     # new chunk starts
4557                     chunk_started = True
4558             
4559             if chunk_started:
4560                 contents.append(document.body[i + 1:j])
4561
4562             # look for potential chunk terminator
4563             # on the last line of the chunk paragraph
4564             if document.body[j - 1] == "@":
4565                 break
4566
4567             # look for subsequent chunk paragraph
4568             i = find_token(document.body, "\\begin_layout", j)
4569             if i == -1:
4570                 break
4571
4572             if get_value(document.body, "\\begin_layout", i) != "Chunk":
4573                 break
4574
4575         file_pos = end = j + 1
4576
4577         # The last chunk should simply have an "@" in it
4578         # or at least end with "@" (can happen if @ is
4579         # preceded by a newline)
4580         lastpar = ''
4581         if len(contents) > 0:
4582             lastpar = ''.join(contents[-1])
4583         if not lastpar.endswith("@"):
4584             document.warning("Unexpected chunk content: chunk not terminated by '@'!")
4585             if len(contents) == 0:
4586                 # convert empty chunk layouts to Standard
4587                 document.body[start] = "\\begin_layout Standard"
4588             continue
4589
4590         if lastpar == "@":
4591             # chunk par only contains "@". Just drop it.
4592             contents.pop()
4593         else:
4594             # chunk par contains more. Only drop the "@".
4595             contents[-1].pop()
4596
4597         # The first line should look like: <<CONTENT>>=
4598         # We want the CONTENT
4599         optarg = ' '.join(contents[0])
4600         optarg.strip()
4601         # We can already have real chunk content in
4602         # the first par (separated from the options by a newline).
4603         # We collect such stuff to re-insert it later.
4604         postoptstuff = []
4605         
4606         match = first_re.search(optarg)
4607         if match:
4608             optarg = match.groups()[0]
4609             if match.groups()[1] != "":
4610                 postopt = False
4611                 for c in contents[0]:
4612                     if c.endswith(">>="):
4613                         postopt = True
4614                         continue
4615                     if postopt:
4616                         postoptstuff.append(c)
4617             # We have stripped everything. This can be deleted.
4618             contents.pop(0)
4619
4620         newstuff = ['\\begin_layout Standard',
4621                     '\\begin_inset Flex Chunk',
4622                     'status open', '',
4623                     '\\begin_layout Plain Layout', '']
4624
4625         # If we have a non-empty optional argument, insert it.
4626         if match and optarg != "":
4627             newstuff.extend(
4628                 ['\\begin_inset Argument 1',
4629                  'status open', '',
4630                  '\\begin_layout Plain Layout',
4631                  optarg,
4632                  '\\end_layout', '',
4633                  '\\end_inset', ''])
4634
4635         # Since we already opened a Plain layout, the first paragraph
4636         # does not need to do that.
4637         did_one_par = False
4638         if postoptstuff:
4639             # we need to replace newlines with new layouts
4640             start_newline = -1
4641             started_text = False
4642             for lno in range(0,len(postoptstuff)):
4643                 if postoptstuff[lno].startswith("\\begin_inset Newline newline"):
4644                     start_newline = lno
4645                 elif start_newline != -1:
4646                     if postoptstuff[lno].startswith("\\end_inset"):
4647                         # replace that bit, but only if we already have some text
4648                         # and we're not at the end except for a blank line
4649                         if started_text and \
4650                           (lno != len(postoptstuff) - 2 or postoptstuff[-1] != ""):
4651                             newstuff.extend(['\\end_layout', '\n', '\\begin_layout Plain Layout', '\n'])
4652                         start_newline = -1
4653                         started_text = True
4654                 else:
4655                     newstuff.extend([postoptstuff[lno]])
4656             newstuff.append('\\end_layout')
4657             did_one_par = True
4658         for c in contents:
4659             if did_one_par:
4660                 newstuff.extend(['', '\\begin_layout Plain Layout', ''])
4661             else:
4662                 did_one_par = True
4663             newstuff.extend(c)
4664             newstuff.append('\\end_layout')
4665
4666         newstuff.extend(['', '\\end_inset', '', '\\end_layout', ''])
4667
4668         document.body[start:end] = newstuff
4669
4670         file_pos += len(newstuff) - (end - start)
4671
4672
4673 def revert_chunks(document):
4674     i = 0
4675     while True:
4676         i = find_token(document.body, "\\begin_inset Flex Chunk", i)
4677         if i == -1:
4678             return
4679
4680         iend = find_end_of_inset(document.body, i)
4681         if iend == -1:
4682             document.warning("Can't find end of Chunk!")
4683             i += 1
4684             continue
4685
4686         # Look for optional argument
4687         have_optarg = False
4688         ostart = find_token(document.body, "\\begin_inset Argument 1", i, iend)
4689         if ostart != -1:
4690             oend = find_end_of_inset(document.body, ostart)
4691             k = find_token(document.body, "\\begin_layout Plain Layout", ostart, oend)
4692             if k == -1:
4693                 document.warning("Malformed LyX document: Can't find argument contents!")
4694             else:
4695                 m = find_end_of_layout(document.body, k)
4696                 optarg = "".join(document.body[k+1:m])
4697                 have_optarg = True
4698
4699             # We now remove the optional argument, so we have something
4700             # uniform on which to work
4701             document.body[ostart : oend + 1] = []
4702             # iend is now invalid
4703             iend = find_end_of_inset(document.body, i)
4704
4705         retval = get_containing_layout(document.body, i)
4706         if not retval:
4707             document.warning("Can't find containing layout for Chunk!")
4708             i = iend
4709             continue
4710         (lname, lstart, lend, pstart)  = retval
4711         # we now want to work through the various paragraphs, and collect their contents
4712         parlist = []
4713         k = i
4714         while True:
4715             k = find_token(document.body, "\\begin_layout Plain Layout", k, lend)
4716             if k == -1:
4717                 break
4718             j = find_end_of_layout(document.body, k)
4719             if j == -1:
4720                 document.warning("Can't find end of layout inside chunk!")
4721                 break
4722             parlist.append(document.body[k+1:j])
4723             k = j
4724         # we now need to wrap all of these paragraphs in chunks
4725         newlines = []
4726         if have_optarg:
4727             newlines.extend(["\\begin_layout Chunk", "", "<<" + optarg + ">>=", "\\end_layout", ""])
4728         for stuff in parlist:
4729             newlines.extend(["\\begin_layout Chunk"] + stuff + ["\\end_layout", ""])
4730         newlines.extend(["\\begin_layout Chunk", "", "@", "\\end_layout", ""])
4731         # replace old content with new content
4732         document.body[lstart : lend + 1] = newlines
4733         i = lstart + len(newlines)
4734         
4735
4736 ##
4737 # Conversion hub
4738 #
4739
4740 supported_versions = ["2.1.0","2.1"]
4741 convert = [
4742            [414, []],
4743            [415, [convert_undertilde]],
4744            [416, []],
4745            [417, [convert_japanese_encodings]],
4746            [418, [convert_justification]],
4747            [419, []],
4748            [420, [convert_biblio_style]],
4749            [421, [convert_longtable_captions]],
4750            [422, [convert_use_packages]],
4751            [423, [convert_use_mathtools]],
4752            [424, [convert_cite_engine_type]],
4753            # No convert_cancel, since cancel will be loaded automatically
4754            # in format 425 without any possibility to switch it off.
4755            # This has been fixed in format 464.
4756            [425, []],
4757            [426, []],
4758            [427, []],
4759            [428, [convert_cell_rotation]],
4760            [429, [convert_table_rotation]],
4761            [430, [convert_listoflistings]],
4762            [431, [convert_use_amssymb]],
4763            [432, []],
4764            [433, [convert_armenian]],
4765            [434, []],
4766            [435, []],
4767            [436, []],
4768            [437, []],
4769            [438, []],
4770            [439, []],
4771            [440, []],
4772            [441, [convert_mdnomath]],
4773            [442, []],
4774            [443, []],
4775            [444, []],
4776            [445, []],
4777            [446, [convert_latexargs]],
4778            [447, [convert_IEEEtran, convert_AASTeX, convert_AGUTeX, convert_IJMP, convert_SIGPLAN, convert_SIGGRAPH, convert_EuropeCV, convert_Initials, convert_ModernCV]],
4779            [448, [convert_literate]],
4780            [449, []],
4781            [450, []],
4782            [451, [convert_beamerargs, convert_againframe_args, convert_corollary_args, convert_quote_args]],
4783            [452, [convert_beamerblocks]],
4784            [453, [convert_use_stmaryrd]],
4785            [454, [convert_overprint]],
4786            [455, []],
4787            [456, [convert_epigraph]],
4788            [457, [convert_use_stackrel]],
4789            [458, [convert_captioninsets, convert_captionlayouts]],
4790            [459, []],
4791            [460, []],
4792            [461, []],
4793            [462, []],
4794            [463, [convert_encodings]],
4795            [464, [convert_use_cancel]],
4796            [465, [convert_lyxframes, remove_endframes]],
4797            [466, []],
4798            [467, []],
4799            [468, []],
4800            [469, []],
4801            [470, []],
4802            [471, [convert_cite_engine_type_default]],
4803            [472, []],
4804            [473, []],
4805            [474, [convert_chunks, cleanup_beamerargs]],
4806           ]
4807
4808 revert =  [
4809            [473, [revert_chunks]],
4810            [472, [revert_tibetan]],
4811            [471, [revert_aa1,revert_aa2]],
4812            [470, [revert_cite_engine_type_default]],
4813            [469, [revert_forced_local_layout]],
4814            [468, [revert_starred_caption]],
4815            [467, [revert_mbox_fbox]],
4816            [466, [revert_iwona_fonts]],
4817            [465, [revert_powerdot_flexes, revert_powerdot_pause, revert_powerdot_itemargs, revert_powerdot_columns]],
4818            [464, []],
4819            [463, [revert_use_cancel]],
4820            [462, [revert_encodings]],
4821            [461, [revert_new_libertines]],
4822            [460, [revert_kurier_fonts]],
4823            [459, [revert_IEEEtran_3]],
4824            [458, [revert_fragileframe, revert_newframes]],
4825            [457, [revert_captioninsets, revert_captionlayouts]],
4826            [456, [revert_use_stackrel]],
4827            [455, [revert_epigraph]],
4828            [454, [revert_frametitle]],
4829            [453, [revert_overprint]],
4830            [452, [revert_use_stmaryrd]],
4831            [451, [revert_beamerblocks]],
4832            [450, [revert_beamerargs, revert_beamerargs2, revert_beamerargs3, revert_beamerflex]],
4833            [449, [revert_garamondx, revert_garamondx_newtxmath]],
4834            [448, [revert_itemargs]],
4835            [447, [revert_literate]],
4836            [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]],
4837            [445, [revert_latexargs]],
4838            [444, [revert_uop]],
4839            [443, [revert_biolinum]],
4840            [442, []],
4841            [441, [revert_newtxmath]],
4842            [440, [revert_mdnomath]],
4843            [439, [revert_mathfonts]],
4844            [438, [revert_minionpro]],
4845            [437, [revert_ipadeco, revert_ipachar]],
4846            [436, [revert_texgyre]],
4847            [435, [revert_mathdesign]],
4848            [434, [revert_txtt]],
4849            [433, [revert_libertine]],
4850            [432, [revert_armenian]],
4851            [431, [revert_languages, revert_ancientgreek]],
4852            [430, [revert_use_amssymb]],
4853            [429, [revert_listoflistings]],
4854            [428, [revert_table_rotation]],
4855            [427, [revert_cell_rotation]],
4856            [426, [revert_tipa]],
4857            [425, [revert_verbatim]],
4858            [424, [revert_cancel]],
4859            [423, [revert_cite_engine_type]],
4860            [422, [revert_use_mathtools]],
4861            [421, [revert_use_packages]],
4862            [420, [revert_longtable_captions]],
4863            [419, [revert_biblio_style]],
4864            [418, [revert_australian]],
4865            [417, [revert_justification]],
4866            [416, [revert_japanese_encodings]],
4867            [415, [revert_negative_space, revert_math_spaces]],
4868            [414, [revert_undertilde]],
4869            [413, [revert_visible_space]]
4870           ]
4871
4872
4873 if __name__ == "__main__":
4874     pass