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