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