]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_1.py
db7e391adedf3bc9664d70adfc6e5bd2a1af0bfe
[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 ###############################################################################
57 ###
58 ### Conversion and reversion routines
59 ###
60 ###############################################################################
61
62 def revert_visible_space(document):
63     "Revert InsetSpace visible into its ERT counterpart"
64     i = 0
65     while True:
66       i = find_token(document.body, "\\begin_inset space \\textvisiblespace{}", i)
67       if i == -1:
68         return
69       end = find_end_of_inset(document.body, i)
70       subst = put_cmd_in_ert("\\textvisiblespace{}")
71       document.body[i:end + 1] = subst
72
73
74 def convert_undertilde(document):
75     " Load undertilde automatically "
76     i = find_token(document.header, "\\use_mathdots" , 0)
77     if i == -1:
78         i = find_token(document.header, "\\use_mhchem" , 0)
79     if i == -1:
80         i = find_token(document.header, "\\use_esint" , 0)
81     if i == -1:
82         document.warning("Malformed LyX document: Can't find \\use_mathdots.")
83         return;
84     j = find_token(document.preamble, "\\usepackage{undertilde}", 0)
85     if j == -1:
86         document.header.insert(i + 1, "\\use_undertilde 0")
87     else:
88         document.header.insert(i + 1, "\\use_undertilde 2")
89         del document.preamble[j]
90
91
92 def revert_undertilde(document):
93     " Load undertilde if used in the document "
94     undertilde = find_token(document.header, "\\use_undertilde" , 0)
95     if undertilde == -1:
96       document.warning("No \\use_undertilde line. Assuming auto.")
97     else:
98       val = get_value(document.header, "\\use_undertilde", undertilde)
99       del document.header[undertilde]
100       try:
101         usetilde = int(val)
102       except:
103         document.warning("Invalid \\use_undertilde value: " + val + ". Assuming auto.")
104         # probably usedots has not been changed, but be safe.
105         usetilde = 1
106
107       if usetilde == 0:
108         # do not load case
109         return
110       if usetilde == 2:
111         # force load case
112         add_to_preamble(document, ["\\usepackage{undertilde}"])
113         return
114
115     # so we are in the auto case. we want to load undertilde if \utilde is used.
116     i = 0
117     while True:
118       i = find_token(document.body, '\\begin_inset Formula', i)
119       if i == -1:
120         return
121       j = find_end_of_inset(document.body, i)
122       if j == -1:
123         document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
124         i += 1
125         continue
126       code = "\n".join(document.body[i:j])
127       if code.find("\\utilde") != -1:
128         add_to_preamble(document, ["\\@ifundefined{utilde}{\\usepackage{undertilde}}"])
129         return
130       i = j
131
132
133 def revert_negative_space(document):
134     "Revert InsetSpace negmedspace and negthickspace into its TeX-code counterpart"
135     i = 0
136     j = 0
137     reverted = False
138     while True:
139       i = find_token(document.body, "\\begin_inset space \\negmedspace{}", i)
140       if i == -1:
141         j = find_token(document.body, "\\begin_inset space \\negthickspace{}", j)
142         if j == -1:
143           # load amsmath in the preamble if not already loaded if we are at the end of checking
144           if reverted == True:
145             i = find_token(document.header, "\\use_amsmath 2", 0)
146             if i == -1:
147               add_to_preamble(document, ["\\@ifundefined{negthickspace}{\\usepackage{amsmath}}"])
148           return
149       if i == -1:
150         return
151       end = find_end_of_inset(document.body, i)
152       subst = put_cmd_in_ert("\\negmedspace{}")
153       document.body[i:end + 1] = subst
154       j = find_token(document.body, "\\begin_inset space \\negthickspace{}", j)
155       if j == -1:
156         return
157       end = find_end_of_inset(document.body, j)
158       subst = put_cmd_in_ert("\\negthickspace{}")
159       document.body[j:end + 1] = subst
160       reverted = True
161
162
163 def revert_math_spaces(document):
164     "Revert formulas with protected custom space and protected hfills to TeX-code"
165     i = 0
166     while True:
167       i = find_token(document.body, "\\begin_inset Formula", i)
168       if i == -1:
169         return
170       j = document.body[i].find("\\hspace*")
171       if j != -1:
172         end = find_end_of_inset(document.body, i)
173         subst = put_cmd_in_ert(document.body[i][21:])
174         document.body[i:end + 1] = subst
175       i = i + 1
176
177
178 def convert_japanese_encodings(document):
179     " Rename the japanese encodings to names understood by platex "
180     jap_enc_dict = {
181         "EUC-JP-pLaTeX": "euc",
182         "JIS-pLaTeX":    "jis",
183         "SJIS-pLaTeX":   "sjis"
184     }
185     i = find_token(document.header, "\\inputencoding" , 0)
186     if i == -1:
187         return
188     val = get_value(document.header, "\\inputencoding", i)
189     if val in jap_enc_dict.keys():
190         document.header[i] = "\\inputencoding %s" % jap_enc_dict[val]
191
192
193 def revert_japanese_encodings(document):
194     " Revert the japanese encodings name changes "
195     jap_enc_dict = {
196         "euc":  "EUC-JP-pLaTeX",
197         "jis":  "JIS-pLaTeX",
198         "sjis": "SJIS-pLaTeX"
199     }
200     i = find_token(document.header, "\\inputencoding" , 0)
201     if i == -1:
202         return
203     val = get_value(document.header, "\\inputencoding", i)
204     if val in jap_enc_dict.keys():
205         document.header[i] = "\\inputencoding %s" % jap_enc_dict[val]
206
207
208 def revert_justification(document):
209     " Revert the \\justification buffer param"
210     if not del_token(document.header, '\\justification', 0):
211         document.warning("Malformed LyX document: Missing \\justification.")
212
213
214 def revert_australian(document):
215     "Set English language variants Australian and Newzealand to English" 
216
217     if document.language == "australian" or document.language == "newzealand": 
218         document.language = "english"
219         i = find_token(document.header, "\\language", 0) 
220         if i != -1: 
221             document.header[i] = "\\language english" 
222     j = 0 
223     while True: 
224         j = find_token(document.body, "\\lang australian", j) 
225         if j == -1:
226             j = find_token(document.body, "\\lang newzealand", 0)
227             if j == -1:
228                 return
229             else:
230                 document.body[j] = document.body[j].replace("\\lang newzealand", "\\lang english")
231         else:
232             document.body[j] = document.body[j].replace("\\lang australian", "\\lang english") 
233         j += 1
234
235
236 def convert_biblio_style(document):
237     "Add a sensible default for \\biblio_style based on the citation engine."
238     i = find_token(document.header, "\\cite_engine", 0)
239     if i != -1:
240         engine = get_value(document.header, "\\cite_engine", i).split("_")[0]
241         style = {"basic": "plain", "natbib": "plainnat", "jurabib": "jurabib"}
242         document.header.insert(i + 1, "\\biblio_style " + style[engine])
243
244
245 def revert_biblio_style(document):
246     "BibTeX insets with default option use the style defined by \\biblio_style."
247     i = find_token(document.header, "\\biblio_style" , 0)
248     if i == -1:
249         document.warning("No \\biblio_style line. Nothing to do.")
250         return
251
252     default_style = get_value(document.header, "\\biblio_style", i)
253     del document.header[i]
254
255     # We are looking for bibtex insets having the default option
256     i = 0
257     while True:
258         i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
259         if i == -1:
260             return
261         j = find_end_of_inset(document.body, i)
262         if j == -1:
263             document.warning("Malformed LyX document: Can't find end of bibtex inset at line " + str(i))
264             i += 1
265             return
266         k = find_token(document.body, "options", i, j)
267         if k != -1:
268             options = get_quoted_value(document.body, "options", k)
269             if "default" in options.split(","):
270                 document.body[k] = 'options "%s"' \
271                     % options.replace("default", default_style)
272         i = j
273
274
275 def handle_longtable_captions(document, forward):
276     begin_table = 0
277     while True:
278         begin_table = find_token(document.body, '<lyxtabular version=', begin_table)
279         if begin_table == -1:
280             break
281         end_table = find_end_of(document.body, begin_table, '<lyxtabular', '</lyxtabular>')
282         if end_table == -1:
283             document.warning("Malformed LyX document: Could not find end of table.")
284             begin_table += 1
285             continue
286         fline = find_token(document.body, "<features", begin_table, end_table)
287         if fline == -1:
288             document.warning("Can't find features for inset at line " + str(begin_table))
289             begin_table += 1
290             continue
291         p = document.body[fline].find("islongtable")
292         if p == -1:
293             # no longtable
294             begin_table += 1
295             continue
296         numrows = get_option_value(document.body[begin_table], "rows")
297         try:
298             numrows = int(numrows)
299         except:
300             document.warning(document.body[begin_table])
301             document.warning("Unable to determine rows!")
302             begin_table = end_table
303             continue
304         begin_row = begin_table
305         for row in range(numrows):
306             begin_row = find_token(document.body, '<row', begin_row, end_table)
307             if begin_row == -1:
308                 document.warning("Can't find row " + str(row + 1))
309                 break
310             end_row = find_end_of(document.body, begin_row, '<row', '</row>')
311             if end_row == -1:
312                 document.warning("Can't find end of row " + str(row + 1))
313                 break
314             if forward:
315                 if (get_option_value(document.body[begin_row], 'caption') == 'true' and
316                     get_option_value(document.body[begin_row], 'endfirsthead') != 'true' and
317                     get_option_value(document.body[begin_row], 'endhead') != 'true' and
318                     get_option_value(document.body[begin_row], 'endfoot') != 'true' and
319                     get_option_value(document.body[begin_row], 'endlastfoot') != 'true'):
320                     document.body[begin_row] = set_option_value(document.body[begin_row], 'caption', 'true", endfirsthead="true')
321             elif get_option_value(document.body[begin_row], 'caption') == 'true':
322                 if get_option_value(document.body[begin_row], 'endfirsthead') == 'true':
323                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endfirsthead', 'false')
324                 if get_option_value(document.body[begin_row], 'endhead') == 'true':
325                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endhead', 'false')
326                 if get_option_value(document.body[begin_row], 'endfoot') == 'true':
327                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endfoot', 'false')
328                 if get_option_value(document.body[begin_row], 'endlastfoot') == 'true':
329                     document.body[begin_row] = set_option_value(document.body[begin_row], 'endlastfoot', 'false')
330             begin_row = end_row
331         # since there could be a tabular inside this one, we 
332         # cannot jump to end.
333         begin_table += 1
334
335
336 def convert_longtable_captions(document):
337     "Add a firsthead flag to caption rows"
338     handle_longtable_captions(document, True)
339
340
341 def revert_longtable_captions(document):
342     "remove head/foot flag from caption rows"
343     handle_longtable_captions(document, False)
344
345
346 def convert_use_packages(document):
347     "use_xxx yyy => use_package xxx yyy"
348     packages = ["amsmath", "esint", "mathdots", "mhchem", "undertilde"]
349     for p in packages:
350         i = find_token(document.header, "\\use_%s" % p, 0)
351         if i != -1:
352             value = get_value(document.header, "\\use_%s" % p, i)
353             document.header[i] = "\\use_package %s %s" % (p, value)
354
355
356 def revert_use_packages(document):
357     "use_package xxx yyy => use_xxx yyy"
358     packages = ["amsmath", "esint", "mathdots", "mhchem", "undertilde"]
359     # the order is arbitrary for the use_package version, and not all packages need to be given.
360     # Ensure a complete list and correct order (important for older LyX versions and especially lyx2lyx)
361     j = 0
362     for p in packages:
363         regexp = re.compile(r'(\\use_package\s+%s)' % p)
364         i = find_re(document.header, regexp, j)
365         if i != -1:
366             value = get_value(document.header, "\\use_package %s" % p, i).split()[1]
367             del document.header[i]
368             j = i
369             document.header.insert(j, "\\use_%s %s"  % (p, value))
370         j = j + 1
371
372
373 def convert_use_mathtools(document):
374     "insert use_package mathtools"
375     i = find_token(document.header, "\\use_package", 0)
376     if i == -1:
377         document.warning("Malformed LyX document: Can't find \\use_package.")
378         return;
379     j = find_token(document.preamble, "\\usepackage{mathtools}", 0)
380     if j == -1:
381         document.header.insert(i + 1, "\\use_package mathtools 0")
382     else:
383         document.header.insert(i + 1, "\\use_package mathtools 2")
384         del document.preamble[j]
385
386
387 def revert_use_mathtools(document):
388     "remove use_package mathtools"
389     regexp = re.compile(r'(\\use_package\s+mathtools)')
390     i = find_re(document.header, regexp, 0)
391     value = "1" # default is auto
392     if i != -1:
393         value = get_value(document.header, "\\use_package" , i).split()[1]
394         del document.header[i]
395     if value == "2": # on
396         add_to_preamble(document, ["\\usepackage{mathtools}"])
397     elif value == "1": # auto
398         commands = ["mathclap", "mathllap", "mathrlap", \
399                     "lgathered", "rgathered", "vcentcolon", "dblcolon", \
400                     "coloneqq", "Coloneqq", "coloneq", "Coloneq", "eqqcolon", \
401                     "Eqqcolon", "eqcolon", "Eqcolon", "colonapprox", \
402                     "Colonapprox", "colonsim", "Colonsim"]
403         i = 0
404         while True:
405             i = find_token(document.body, '\\begin_inset Formula', i)
406             if i == -1:
407                 return
408             j = find_end_of_inset(document.body, i)
409             if j == -1:
410                 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
411                 i += 1
412                 continue
413             code = "\n".join(document.body[i:j])
414             for c in commands:
415                 if code.find("\\%s" % c) != -1:
416                     add_to_preamble(document, ["\\usepackage{mathtools}"])
417                     return
418             i = j
419
420
421 def convert_use_stmaryrd(document):
422     "insert use_package stmaryrd"
423     i = find_token(document.header, "\\use_package", 0)
424     if i == -1:
425         document.warning("Malformed LyX document: Can't find \\use_package.")
426         return;
427     j = find_token(document.preamble, "\\usepackage{stmaryrd}", 0)
428     if j == -1:
429         document.header.insert(i + 1, "\\use_package stmaryrd 0")
430     else:
431         document.header.insert(i + 1, "\\use_package stmaryrd 2")
432         del document.preamble[j]
433
434
435 def revert_use_stmaryrd(document):
436     "remove use_package stmaryrd"
437     regexp = re.compile(r'(\\use_package\s+stmaryrd)')
438     i = find_re(document.header, regexp, 0)
439     value = "1" # default is auto
440     if i != -1:
441         value = get_value(document.header, "\\use_package" , i).split()[1]
442         del document.header[i]
443     if value == "2": # on
444         add_to_preamble(document, ["\\usepackage{stmaryrd}"])
445     elif value == "1": # auto
446         commands = ["shortleftarrow", "shortrightarrow", "shortuparrow", \
447                     "shortdownarrow", "Yup", "Ydown", "Yleft", "Yright", \
448                     "varcurlyvee", "varcurlywedge", "minuso", "baro", \
449                     "sslash", "bbslash", "moo", "varotimes", "varoast", \
450                     "varobar", "varodot", "varoslash", "varobslash", \
451                     "varocircle", "varoplus", "varominus", "boxast", \
452                     "boxbar", "boxdot", "boxslash", "boxbslash", "boxcircle", \
453                     "boxbox", "boxempty", "merge", "vartimes", \
454                     "fatsemi", "sswarrow", "ssearrow", "curlywedgeuparrow", \
455                     "curlywedgedownarrow", "fatslash", "fatbslash", "lbag", \
456                     "rbag", "varbigcirc", "leftrightarroweq", \
457                     "curlyveedownarrow", "curlyveeuparrow", "nnwarrow", \
458                     "nnearrow", "leftslice", "rightslice", "varolessthan", \
459                     "varogreaterthan", "varovee", "varowedge", "talloblong", \
460                     "interleave", "obar", "obslash", "olessthan", \
461                     "ogreaterthan", "ovee", "owedge", "oblong", "inplus", \
462                     "niplus", "nplus", "subsetplus", "supsetplus", \
463                     "subsetpluseq", "supsetpluseq", "Lbag", "Rbag", \
464                     "llbracket", "rrbracket", "llparenthesis", \
465                     "rrparenthesis", "binampersand", "bindnasrepma", \
466                     "trianglelefteqslant", "trianglerighteqslant", \
467                     "ntrianglelefteqslant", "ntrianglerighteqslant", \
468                     "llfloor", "rrfloor", "llceil", "rrceil", "arrownot", \
469                     "Arrownot", "Mapstochar", "mapsfromchar", "Mapsfromchar", \
470                     "leftrightarrowtriangle", "leftarrowtriangle", \
471                     "rightarrowtriangle", \
472                     "bigcurlyvee", "bigcurlywedge", "bigsqcap", "bigbox", \
473                     "bigparallel", "biginterleave", "bignplus", \
474                     "varcopyright", "longarrownot", "Longarrownot", \
475                     "Mapsto", "mapsfrom", "Mapsfrom" "Longmapsto", \
476                     "longmapsfrom", "Longmapsfrom"]
477         # commands provided by stmaryrd.sty but LyX uses other packages:
478         # lightning, bigtriangledown, bigtriangleup
479
480         i = 0
481         while True:
482             i = find_token(document.body, '\\begin_inset Formula', i)
483             if i == -1:
484                 return
485             j = find_end_of_inset(document.body, i)
486             if j == -1:
487                 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
488                 i += 1
489                 continue
490             code = "\n".join(document.body[i:j])
491             for c in commands:
492                 if code.find("\\%s" % c) != -1:
493                     add_to_preamble(document, ["\\usepackage{stmaryrd}"])
494                     return
495             i = j
496
497
498 def convert_cite_engine_type(document):
499     "Determine the \\cite_engine_type from the citation engine."
500     i = find_token(document.header, "\\cite_engine", 0)
501     if i == -1:
502         return
503     engine = get_value(document.header, "\\cite_engine", i)
504     if "_" in engine:
505         engine, type = engine.split("_")
506     else:
507         type = {"basic": "numerical", "jurabib": "authoryear"}[engine]
508     document.header[i] = "\\cite_engine " + engine
509     document.header.insert(i + 1, "\\cite_engine_type " + type)
510
511
512 def revert_cite_engine_type(document):
513     "Natbib had the type appended with an underscore."
514     engine_type = "numerical"
515     i = find_token(document.header, "\\cite_engine_type" , 0)
516     if i == -1:
517         document.warning("No \\cite_engine_type line. Assuming numerical.")
518     else:
519         engine_type = get_value(document.header, "\\cite_engine_type", i)
520         del document.header[i]
521
522     # We are looking for the natbib citation engine
523     i = find_token(document.header, "\\cite_engine natbib", 0)
524     if i == -1:
525         return
526     document.header[i] = "\\cite_engine natbib_" + engine_type
527
528
529 def revert_cancel(document):
530     "add cancel to the preamble if necessary"
531     commands = ["cancelto", "cancel", "bcancel", "xcancel"]
532     i = 0
533     while True:
534         i = find_token(document.body, '\\begin_inset Formula', i)
535         if i == -1:
536             return
537         j = find_end_of_inset(document.body, i)
538         if j == -1:
539             document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
540             i += 1
541             continue
542         code = "\n".join(document.body[i:j])
543         for c in commands:
544             if code.find("\\%s" % c) != -1:
545                 add_to_preamble(document, ["\\usepackage{cancel}"])
546                 return
547         i = j
548
549
550 def revert_verbatim(document):
551     " Revert verbatim einvironments completely to TeX-code. "
552     i = 0
553     consecutive = False
554     subst_end = ['\end_layout', '', '\\begin_layout Plain Layout',
555                  '\end_layout', '',
556                  '\\begin_layout Plain Layout', '', '',
557                  '\\backslash', '',
558                  'end{verbatim}',
559                  '\\end_layout', '', '\\end_inset',
560                  '', '', '\\end_layout']
561     subst_begin = ['\\begin_layout Standard', '\\noindent',
562                    '\\begin_inset ERT', 'status collapsed', '',
563                    '\\begin_layout Plain Layout', '', '', '\\backslash',
564                    'begin{verbatim}',
565                    '\\end_layout', '', '\\begin_layout Plain Layout', '']
566     while 1:
567         i = find_token(document.body, "\\begin_layout Verbatim", i)
568         if i == -1:
569             return
570         j = find_end_of_layout(document.body, i)
571         if j == -1:
572             document.warning("Malformed lyx document: Can't find end of Verbatim layout")
573             i += 1
574             continue
575         # delete all line breaks insets (there are no other insets)
576         l = i
577         while 1:
578             n = find_token(document.body, "\\begin_inset Newline newline", l)
579             if n == -1:
580                 n = find_token(document.body, "\\begin_inset Newline linebreak", l)
581                 if n == -1:
582                     break
583             m = find_end_of_inset(document.body, n)
584             del(document.body[m:m+1])
585             document.body[n:n+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
586             l += 1
587             j += 1
588         # consecutive verbatim environments need to be connected
589         k = find_token(document.body, "\\begin_layout Verbatim", j)
590         if k == j + 2 and consecutive == False:
591             consecutive = True
592             document.body[j:j+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
593             document.body[i:i+1] = subst_begin
594             continue
595         if k == j + 2 and consecutive == True:
596             document.body[j:j+1] = ['\end_layout', '', '\\begin_layout Plain Layout']
597             del(document.body[i:i+1])
598             continue
599         if k != j + 2 and consecutive == True:
600             document.body[j:j+1] = subst_end
601             # the next paragraph must not be indented
602             document.body[j+19:j+19] = ['\\noindent']
603             del(document.body[i:i+1])
604             consecutive = False
605             continue
606         else:
607             document.body[j:j+1] = subst_end
608             # the next paragraph must not be indented
609             document.body[j+19:j+19] = ['\\noindent']
610             document.body[i:i+1] = subst_begin
611
612
613 def revert_tipa(document):
614     " Revert native TIPA insets to mathed or ERT. "
615     i = 0
616     while 1:
617         i = find_token(document.body, "\\begin_inset IPA", i)
618         if i == -1:
619             return
620         j = find_end_of_inset(document.body, i)
621         if j == -1:
622             document.warning("Malformed lyx document: Can't find end of IPA inset")
623             i += 1
624             continue
625         Multipar = False
626         n = find_token(document.body, "\\begin_layout", i, j)
627         if n == -1:
628             document.warning("Malformed lyx document: IPA inset has no embedded layout")
629             i += 1
630             continue
631         m = find_end_of_layout(document.body, n)
632         if m == -1:
633             document.warning("Malformed lyx document: Can't find end of embedded layout")
634             i += 1
635             continue
636         content = document.body[n+1:m]
637         p = find_token(document.body, "\\begin_layout", m, j)
638         if p != -1 or len(content) > 1:
639             Multipar = True
640             content = document.body[i+1:j]
641         if Multipar:
642             # IPA insets with multiple pars need to be wrapped by \begin{IPA}...\end{IPA}
643             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}")
644             add_to_preamble(document, ["\\usepackage{tipa,tipx}"])
645         else:
646             # single-par IPA insets can be reverted to mathed
647             document.body[i:j+1] = ["\\begin_inset Formula $\\text{\\textipa{" + content[0] + "}}$", "\\end_inset"]
648         i = j
649
650
651 def revert_cell_rotation(document):
652   "Revert cell rotations to TeX-code"
653
654   load_rotating = False
655   i = 0
656   try:
657     while True:
658       # first, let's find out if we need to do anything
659       i = find_token(document.body, '<cell ', i)
660       if i == -1:
661         return
662       j = document.body[i].find('rotate="')
663       if j != -1:
664         k = document.body[i].find('"', j + 8)
665         value = document.body[i][j + 8 : k]
666         if value == "0":
667           rgx = re.compile(r' rotate="[^"]+?"')
668           # remove rotate option
669           document.body[i] = rgx.sub('', document.body[i])
670         elif value == "90":
671           rgx = re.compile(r' rotate="[^"]+?"')
672           document.body[i] = rgx.sub('rotate="true"', document.body[i])
673         else:
674           rgx = re.compile(r' rotate="[^"]+?"')
675           load_rotating = True
676           # remove rotate option
677           document.body[i] = rgx.sub('', document.body[i])
678           # write ERT
679           document.body[i + 5 : i + 5] = \
680             put_cmd_in_ert("\\end{turn}")
681           document.body[i + 4 : i + 4] = \
682             put_cmd_in_ert("\\begin{turn}{" + value + "}")
683         
684       i += 1
685         
686   finally:
687     if load_rotating:
688       add_to_preamble(document, ["\\@ifundefined{turnbox}{\usepackage{rotating}}{}"])
689
690
691 def convert_cell_rotation(document):
692     'Convert cell rotation statements from "true" to "90"'
693
694     i = 0
695     while True:
696       # first, let's find out if we need to do anything
697       i = find_token(document.body, '<cell ', i)
698       if i == -1:
699         return
700       j = document.body[i].find('rotate="true"')
701       if j != -1:
702         rgx = re.compile(r'rotate="[^"]+?"')
703         # convert "true" to "90"
704         document.body[i] = rgx.sub('rotate="90"', document.body[i])
705         
706       i += 1
707
708
709 def revert_table_rotation(document):
710   "Revert table rotations to TeX-code"
711
712   load_rotating = False
713   i = 0
714   try:
715     while True:
716       # first, let's find out if we need to do anything
717       i = find_token(document.body, '<features ', i)
718       if i == -1:
719         return
720       j = document.body[i].find('rotate="')
721       if j != -1:
722         end_table = find_token(document.body, '</lyxtabular>', j)
723         k = document.body[i].find('"', j + 8)
724         value = document.body[i][j + 8 : k]
725         if value == "0":
726           rgx = re.compile(r' rotate="[^"]+?"')
727           # remove rotate option
728           document.body[i] = rgx.sub('', document.body[i])
729         elif value == "90":
730           rgx = re.compile(r'rotate="[^"]+?"')
731           document.body[i] = rgx.sub('rotate="true"', document.body[i])
732         else:
733           rgx = re.compile(r' rotate="[^"]+?"')
734           load_rotating = True
735           # remove rotate option
736           document.body[i] = rgx.sub('', document.body[i])
737           # write ERT
738           document.body[end_table + 3 : end_table + 3] = \
739             put_cmd_in_ert("\\end{turn}")
740           document.body[i - 2 : i - 2] = \
741             put_cmd_in_ert("\\begin{turn}{" + value + "}")
742         
743       i += 1
744         
745   finally:
746     if load_rotating:
747       add_to_preamble(document, ["\\@ifundefined{turnbox}{\usepackage{rotating}}{}"])
748
749
750 def convert_table_rotation(document):
751     'Convert table rotation statements from "true" to "90"'
752
753     i = 0
754     while True:
755       # first, let's find out if we need to do anything
756       i = find_token(document.body, '<features ', i)
757       if i == -1:
758         return
759       j = document.body[i].find('rotate="true"')
760       if j != -1:
761         rgx = re.compile(r'rotate="[^"]+?"')
762         # convert "true" to "90"
763         document.body[i] = rgx.sub('rotate="90"', document.body[i])
764         
765       i += 1
766
767
768 def convert_listoflistings(document):
769     'Convert ERT \lstlistoflistings to TOC lstlistoflistings inset'
770     # We can support roundtrip because the command is so simple
771     i = 0
772     while True:
773         i = find_token(document.body, "\\begin_inset ERT", i)
774         if i == -1:
775             return
776         j = find_end_of_inset(document.body, i)
777         if j == -1:
778             document.warning("Malformed lyx document: Can't find end of ERT inset")
779             i += 1
780             continue
781         ert = get_ert(document.body, i)
782         if ert == "\\lstlistoflistings{}":
783             document.body[i:j] = ["\\begin_inset CommandInset toc", "LatexCommand lstlistoflistings", ""]
784             i = i + 4
785         else:
786             i = j + 1
787
788
789 def revert_listoflistings(document):
790     'Convert TOC lstlistoflistings inset to ERT lstlistoflistings'
791     i = 0
792     while True:
793         i = find_token(document.body, "\\begin_inset CommandInset toc", i)
794         if i == -1:
795             return
796         if document.body[i+1] == "LatexCommand lstlistoflistings":
797             j = find_end_of_inset(document.body, i)
798             if j == -1:
799                 document.warning("Malformed lyx document: Can't find end of TOC inset")
800                 i += 1
801                 continue
802             subst = put_cmd_in_ert("\\lstlistoflistings{}")
803             document.body[i:j+1] = subst
804             add_to_preamble(document, ["\\usepackage{listings}"])
805         i = i + 1
806
807
808 def convert_use_amssymb(document):
809     "insert use_package amssymb"
810     regexp = re.compile(r'(\\use_package\s+amsmath)')
811     i = find_re(document.header, regexp, 0)
812     if i == -1:
813         document.warning("Malformed LyX document: Can't find \\use_package amsmath.")
814         return;
815     value = get_value(document.header, "\\use_package" , i).split()[1]
816     useamsmath = 0
817     try:
818         useamsmath = int(value)
819     except:
820         document.warning("Invalid \\use_package amsmath: " + value + ". Assuming auto.")
821         useamsmath = 1
822     j = find_token(document.preamble, "\\usepackage{amssymb}", 0)
823     if j == -1:
824         document.header.insert(i + 1, "\\use_package amssymb %d" % useamsmath)
825     else:
826         document.header.insert(i + 1, "\\use_package amssymb 2")
827         del document.preamble[j]
828
829
830 def revert_use_amssymb(document):
831     "remove use_package amssymb"
832     regexp1 = re.compile(r'(\\use_package\s+amsmath)')
833     regexp2 = re.compile(r'(\\use_package\s+amssymb)')
834     i = find_re(document.header, regexp1, 0)
835     j = find_re(document.header, regexp2, 0)
836     value1 = "1" # default is auto
837     value2 = "1" # default is auto
838     if i != -1:
839         value1 = get_value(document.header, "\\use_package" , i).split()[1]
840     if j != -1:
841         value2 = get_value(document.header, "\\use_package" , j).split()[1]
842         del document.header[j]
843     if value1 != value2 and value2 == "2": # on
844         add_to_preamble(document, ["\\usepackage{amssymb}"])
845
846
847 def revert_ancientgreek(document):
848     "Set the document language for ancientgreek to greek" 
849
850     if document.language == "ancientgreek": 
851         document.language = "greek"
852         i = find_token(document.header, "\\language", 0) 
853         if i != -1: 
854             document.header[i] = "\\language greek" 
855     j = 0 
856     while True: 
857         j = find_token(document.body, "\\lang ancientgreek", j) 
858         if j == -1:
859             return
860         else:
861             document.body[j] = document.body[j].replace("\\lang ancientgreek", "\\lang greek") 
862         j += 1
863
864
865 def revert_languages(document):
866     "Set the document language for new supported languages to English" 
867
868     languages = [
869                  "coptic", "divehi", "hindi", "kurmanji", "lao", "marathi", "occitan", "sanskrit",
870                  "syriac", "tamil", "telugu", "urdu"
871                 ]
872     for n in range(len(languages)):
873         if document.language == languages[n]:
874             document.language = "english"
875             i = find_token(document.header, "\\language", 0) 
876             if i != -1: 
877                 document.header[i] = "\\language english" 
878         j = 0
879         while j < len(document.body): 
880             j = find_token(document.body, "\\lang " + languages[n], j)
881             if j != -1:
882                 document.body[j] = document.body[j].replace("\\lang " + languages[n], "\\lang english")
883                 j += 1
884             else:
885                 j = len(document.body)
886
887
888 def convert_armenian(document):
889     "Use polyglossia and thus non-TeX fonts for Armenian" 
890
891     if document.language == "armenian": 
892         i = find_token(document.header, "\\use_non_tex_fonts", 0) 
893         if i != -1: 
894             document.header[i] = "\\use_non_tex_fonts true" 
895
896
897 def revert_armenian(document):
898     "Use ArmTeX and thus TeX fonts for Armenian" 
899
900     if document.language == "armenian": 
901         i = find_token(document.header, "\\use_non_tex_fonts", 0) 
902         if i != -1: 
903             document.header[i] = "\\use_non_tex_fonts false" 
904
905
906 def revert_libertine(document):
907     " Revert native libertine font definition to LaTeX " 
908
909     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
910         i = find_token(document.header, "\\font_roman libertine", 0)
911         if i != -1:
912             osf = False
913             j = find_token(document.header, "\\font_osf true", 0)
914             if j != -1:
915                 osf = True
916             preamble = "\\usepackage"
917             if osf:
918                 document.header[j] = "\\font_osf false"
919             else:
920                 preamble += "[lining]"
921             preamble += "{libertine-type1}"
922             add_to_preamble(document, [preamble])
923             document.header[i] = "\\font_roman default"
924
925
926 def revert_txtt(document):
927     " Revert native txtt font definition to LaTeX " 
928
929     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
930         i = find_token(document.header, "\\font_typewriter txtt", 0)
931         if i != -1:
932             preamble = "\\renewcommand{\\ttdefault}{txtt}"
933             add_to_preamble(document, [preamble])
934             document.header[i] = "\\font_typewriter default"
935
936
937 def revert_mathdesign(document):
938     " Revert native mathdesign font definition to LaTeX " 
939
940     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
941         mathdesign_dict = {
942         "mdbch":  "charter",
943         "mdput":  "utopia",
944         "mdugm":  "garamond"
945         }
946         i = find_token(document.header, "\\font_roman", 0)
947         if i == -1:
948             return
949         val = get_value(document.header, "\\font_roman", i)
950         if val in mathdesign_dict.keys():
951             preamble = "\\usepackage[%s" % mathdesign_dict[val]
952             expert = False
953             j = find_token(document.header, "\\font_osf true", 0)
954             if j != -1:
955                 expert = True
956                 document.header[j] = "\\font_osf false"
957             l = find_token(document.header, "\\font_sc true", 0)
958             if l != -1:
959                 expert = True
960                 document.header[l] = "\\font_sc false"
961             if expert:
962                 preamble += ",expert"
963             preamble += "]{mathdesign}"
964             add_to_preamble(document, [preamble])
965             document.header[i] = "\\font_roman default"
966
967
968 def revert_texgyre(document):
969     " Revert native TeXGyre font definition to LaTeX " 
970
971     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
972         texgyre_fonts = ["tgadventor", "tgbonum", "tgchorus", "tgcursor", \
973                          "tgheros", "tgpagella", "tgschola", "tgtermes"]
974         i = find_token(document.header, "\\font_roman", 0)
975         if i != -1:
976             val = get_value(document.header, "\\font_roman", i)
977             if val in texgyre_fonts:
978                 preamble = "\\usepackage{%s}" % val
979                 add_to_preamble(document, [preamble])
980                 document.header[i] = "\\font_roman default"
981         i = find_token(document.header, "\\font_sans", 0)
982         if i != -1:
983             val = get_value(document.header, "\\font_sans", i)
984             if val in texgyre_fonts:
985                 preamble = "\\usepackage{%s}" % val
986                 add_to_preamble(document, [preamble])
987                 document.header[i] = "\\font_sans default"
988         i = find_token(document.header, "\\font_typewriter", 0)
989         if i != -1:
990             val = get_value(document.header, "\\font_typewriter", i)
991             if val in texgyre_fonts:
992                 preamble = "\\usepackage{%s}" % val
993                 add_to_preamble(document, [preamble])
994                 document.header[i] = "\\font_typewriter default"
995
996
997 def revert_ipadeco(document):
998     " Revert IPA decorations to ERT "
999     i = 0
1000     while True:
1001       i = find_token(document.body, "\\begin_inset IPADeco", i)
1002       if i == -1:
1003           return
1004       end = find_end_of_inset(document.body, i)
1005       if end == -1:
1006           document.warning("Can't find end of inset at line " + str(i))
1007           i += 1
1008           continue
1009       line = document.body[i]
1010       rx = re.compile(r'\\begin_inset IPADeco (.*)$')
1011       m = rx.match(line)
1012       decotype = m.group(1)
1013       if decotype != "toptiebar" and decotype != "bottomtiebar":
1014           document.warning("Invalid IPADeco type: " + decotype)
1015           i = end
1016           continue
1017       blay = find_token(document.body, "\\begin_layout Plain Layout", i, end)
1018       if blay == -1:
1019           document.warning("Can't find layout for inset at line " + str(i))
1020           i = end
1021           continue
1022       bend = find_end_of_layout(document.body, blay)
1023       if bend == -1:
1024           document.warning("Malformed LyX document: Could not find end of IPADeco inset's layout.")
1025           i = end
1026           continue
1027       substi = ["\\begin_inset ERT", "status collapsed", "",
1028                 "\\begin_layout Plain Layout", "", "", "\\backslash", 
1029                 decotype + "{", "\\end_layout", "", "\\end_inset"]
1030       substj = ["\\size default", "", "\\begin_inset ERT", "status collapsed", "",
1031                 "\\begin_layout Plain Layout", "", "}", "\\end_layout", "", "\\end_inset"]
1032       # do the later one first so as not to mess up the numbering
1033       document.body[bend:end + 1] = substj
1034       document.body[i:blay + 1] = substi
1035       i = end + len(substi) + len(substj) - (end - bend) - (blay - i) - 2
1036       add_to_preamble(document, "\\usepackage{tipa}")
1037
1038
1039 def revert_ipachar(document):
1040     ' Revert \\IPAChar to ERT '
1041     i = 0
1042     found = False
1043     while i < len(document.body):
1044         m = re.match(r'(.*)\\IPAChar \\(\w+\{\w+\})(.*)', document.body[i])
1045         if m:
1046             found = True
1047             before = m.group(1)
1048             ipachar = m.group(2)
1049             after = m.group(3)
1050             subst = [before,
1051                      '\\begin_inset ERT',
1052                      'status collapsed', '',
1053                      '\\begin_layout Standard',
1054                      '', '', '\\backslash',
1055                      ipachar,
1056                      '\\end_layout', '',
1057                      '\\end_inset', '',
1058                      after]
1059             document.body[i: i+1] = subst
1060             i = i + len(subst)
1061         else:
1062             i = i + 1
1063     if found:
1064         add_to_preamble(document, "\\usepackage{tone}")
1065
1066
1067 def revert_minionpro(document):
1068     " Revert native MinionPro font definition to LaTeX " 
1069
1070     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1071         i = find_token(document.header, "\\font_roman minionpro", 0)
1072         if i != -1:
1073             osf = False
1074             j = find_token(document.header, "\\font_osf true", 0)
1075             if j != -1:
1076                 osf = True
1077             preamble = "\\usepackage"
1078             if osf:
1079                 document.header[j] = "\\font_osf false"
1080             else:
1081                 preamble += "[lf]"
1082             preamble += "{MinionPro}"
1083             add_to_preamble(document, [preamble])
1084             document.header[i] = "\\font_roman default"
1085
1086
1087 def revert_mathfonts(document):
1088     " Revert native math font definitions to LaTeX " 
1089
1090     i = find_token(document.header, "\\font_math", 0)
1091     if i == -1:
1092        return
1093     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1094         val = get_value(document.header, "\\font_math", i)
1095         if val == "eulervm":
1096             add_to_preamble(document, "\\usepackage{eulervm}")
1097         elif val == "default":
1098             mathfont_dict = {
1099             "lmodern":  "\\renewcommand{\\rmdefault}{lmr}",
1100             "minionpro":  "\\usepackage[onlytext,lf]{MinionPro}",
1101             "minionpro-osf":  "\\usepackage[onlytext]{MinionPro}",
1102             "palatino":  "\\renewcommand{\\rmdefault}{ppl}",
1103             "palatino-osf":  "\\renewcommand{\\rmdefault}{pplj}",
1104             "times":  "\\renewcommand{\\rmdefault}{ptm}",
1105             "utopia":  "\\renewcommand{\\rmdefault}{futs}",
1106             "utopia-osf":  "\\renewcommand{\\rmdefault}{futj}",
1107             }
1108             j = find_token(document.header, "\\font_roman", 0)
1109             if j != -1:
1110                 rm = get_value(document.header, "\\font_roman", j)
1111                 k = find_token(document.header, "\\font_osf true", 0)
1112                 if k != -1:
1113                     rm += "-osf"
1114                 if rm in mathfont_dict.keys():
1115                     add_to_preamble(document, mathfont_dict[rm])
1116                     document.header[j] = "\\font_roman default"
1117                     if k != -1:
1118                         document.header[k] = "\\font_osf false"
1119     del document.header[i]
1120
1121
1122 def revert_mdnomath(document):
1123     " Revert mathdesign and fourier without math " 
1124
1125     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1126         mathdesign_dict = {
1127         "md-charter": "mdbch",
1128         "md-utopia": "mdput",
1129         "md-garamond": "mdugm"
1130         }
1131         i = find_token(document.header, "\\font_roman", 0)
1132         if i == -1:
1133             return
1134         val = get_value(document.header, "\\font_roman", i)
1135         if val in mathdesign_dict.keys():
1136             j = find_token(document.header, "\\font_math", 0)
1137             if j == -1:
1138                 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1139             mval = get_value(document.header, "\\font_math", j)
1140             if mval == "default":
1141                 document.header[i] = "\\font_roman default"
1142                 add_to_preamble(document, "\\renewcommand{\\rmdefault}{%s}" % mathdesign_dict[val])
1143             else:
1144                 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1145
1146
1147 def convert_mdnomath(document):
1148     " Change mathdesign font name " 
1149
1150     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1151         mathdesign_dict = {
1152         "mdbch":  "md-charter",
1153         "mdput":  "md-utopia",
1154         "mdugm":  "md-garamond"
1155         }
1156         i = find_token(document.header, "\\font_roman", 0)
1157         if i == -1:
1158             return
1159         val = get_value(document.header, "\\font_roman", i)
1160         if val in mathdesign_dict.keys():
1161              document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1162
1163
1164 def revert_newtxmath(document):
1165     " Revert native newtxmath definitions to LaTeX " 
1166
1167     i = find_token(document.header, "\\font_math", 0)
1168     if i == -1:
1169        return
1170     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1171         val = get_value(document.header, "\\font_math", i)
1172         mathfont_dict = {
1173         "libertine-ntxm":  "\\usepackage[libertine]{newtxmath}",
1174         "minion-ntxm":  "\\usepackage[minion]{newtxmath}",
1175         "newtxmath":  "\\usepackage{newtxmath}",
1176         }
1177         if val in mathfont_dict.keys():
1178             add_to_preamble(document, mathfont_dict[val])
1179             document.header[i] = "\\font_math auto"
1180
1181
1182 def revert_biolinum(document):
1183     " Revert native biolinum font definition to LaTeX " 
1184
1185     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1186         i = find_token(document.header, "\\font_sans biolinum", 0)
1187         if i != -1:
1188             osf = False
1189             j = find_token(document.header, "\\font_osf true", 0)
1190             if j != -1:
1191                 osf = True
1192             preamble = "\\usepackage"
1193             if not osf:
1194                 preamble += "[lf]"
1195             preamble += "{biolinum-type1}"
1196             add_to_preamble(document, [preamble])
1197             document.header[i] = "\\font_sans default"
1198
1199
1200 def revert_uop(document):
1201     " Revert native URW Classico (Optima) font definition to LaTeX "
1202
1203     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1204         i = find_token(document.header, "\\font_sans uop", 0)
1205         if i != -1:
1206                 preamble = "\\renewcommand{\\sfdefault}{uop}"
1207                 add_to_preamble(document, [preamble])
1208                 document.header[i] = "\\font_sans default"
1209
1210
1211 def convert_latexargs(document):
1212     " Convert InsetArgument to new syntax "
1213
1214     if find_token(document.body, "\\begin_inset Argument", 0) == -1:
1215         # nothing to do.
1216         return
1217
1218     # A list of layouts (document classes) with only optional or no arguments.
1219     # These can be safely converted to the new syntax
1220     # (I took the liberty to add some of my personal layouts/modules here; JSP)
1221     safe_layouts = ["aa", "aapaper", "aastex", "achemso", "acmsiggraph", "AEA",
1222                     "agu-dtd", "agums", "agutex", "amsart", "amsbook", "apa",
1223                     "arab-article", "armenian-article", "article-beamer", "article",
1224                     "beamer", "book", "broadway", "chess", "cl2emult", "ctex-article",
1225                     "ctex-book", "ctex-report", "dinbrief", "docbook-book", "docbook-chapter",
1226                     "docbook", "docbook-section", "doublecol-new", "dtk", "ectaart", "egs",
1227                     "elsarticle", "elsart", "entcs", "europecv", "extarticle", "extbook",
1228                     "extletter", "extreport", "foils", "frletter", "g-brief2", "g-brief",
1229                     "heb-article", "heb-letter", "hollywood", "IEEEtran", "ijmpc", "ijmpd",
1230                     "iopart", "isprs", "jarticle", "jasatex", "jbook", "jgrga", "jreport",
1231                     "jsarticle", "jsbeamer", "jsbook", "jss", "kluwer", "latex8", "letter", "lettre",
1232                     "literate-article", "literate-book", "literate-report", "llncs", "ltugboat",
1233                     "memoir", "moderncv", "mwart", "mwbk", "mwrep", "paper", "powerdot",
1234                     "recipebook", "report", "revtex4", "revtex", "scrartcl", "scrarticle-beamer",
1235                     "scrbook", "scrlettr", "scrlttr2", "scrreprt", "seminar", "siamltex",
1236                     "sigplanconf", "simplecv", "singlecol", "singlecol-new", "slides", "spie",
1237                     "svglobal3", "svglobal", "svjog", "svmono", "svmult", "svprobth", "tarticle",
1238                     "tbook", "treport", "tufte-book", "tufte-handout"]
1239     # A list of "safe" modules, same as above
1240     safe_modules = ["biblatex", "beameraddons", "beamersession", "braille", "customHeadersFooters",
1241                     "endnotes", "enumitem", "eqs-within-sections", "figs-within-sections", "fix-cm",
1242                     "fixltx2e", "foottoend", "hanging", "jscharstyles", "knitr", "lilypond",
1243                     "linguistics", "linguisticx", "logicalmkup", "minimalistic", "nomindex", "noweb",
1244                     "pdfcomment", "sweave", "tabs-within-sections", "theorems-ams-bytype",
1245                     "theorems-ams-extended-bytype", "theorems-ams-extended", "theorems-ams", "theorems-bytype",
1246                     "theorems-chap-bytype", "theorems-chap", "theorems-named", "theorems-sec-bytype",
1247                     "theorems-sec", "theorems-starred", "theorems-std", "todonotes"]
1248     # Modules we need to take care of
1249     caveat_modules = ["initials"]
1250     # information about the relevant styles in caveat_modules (number of opt and req args)
1251     # use this if we get more caveat_modules. For now, use hard coding (see below).
1252     # initials = [{'Layout' : 'Initial', 'opt' : 1, 'req' : 1}]
1253
1254     # Is this a known safe layout?
1255     safe_layout = document.textclass in safe_layouts
1256     if not safe_layout:
1257         document.warning("Lyx2lyx knows nothing about textclass '%s'. "
1258                          "Please check if short title insets have been converted correctly."
1259                          % document.textclass)
1260     # Do we use unsafe or unknown modules
1261     mods = document.get_module_list()
1262     unknown_modules = False
1263     used_caveat_modules = list()
1264     for mod in mods:
1265         if mod in safe_modules:
1266             continue
1267         if mod in caveat_modules:
1268             used_caveat_modules.append(mod)
1269             continue
1270         unknown_modules = True
1271         document.warning("Lyx2lyx knows nothing about module '%s'. "
1272                          "Please check if short title insets have been converted correctly."
1273                          % mod)
1274
1275     i = 0
1276     while True:
1277         i = find_token(document.body, "\\begin_inset Argument", i)
1278         if i == -1:
1279             return
1280
1281         if not safe_layout or unknown_modules:
1282             # We cannot do more here since we have no access to this layout.
1283             # InsetArgument itself will do the real work
1284             # (see InsetArgument::updateBuffer())
1285             document.body[i] = "\\begin_inset Argument 999"
1286             i = i + 1
1287             continue
1288         
1289         # Find containing paragraph layout
1290         parent = get_containing_layout(document.body, i)
1291         if parent == False:
1292             document.warning("Malformed lyx document: Can't find parent paragraph layout")
1293             i = i + 1
1294             continue
1295         parbeg = parent[1]
1296         parend = parent[2]
1297         allowed_opts = -1
1298         first_req = -1
1299         if len(used_caveat_modules) > 0:
1300             # We know for now that this must be the initials module with the Initial layout
1301             # If we get more such modules, we need some automating.
1302             if parent[0] == "Initial":
1303                 # Layout has 1 opt and 1 req arg.
1304                 # Count the actual arguments
1305                 actualargs = 0
1306                 for p in range(parbeg, parend):
1307                     if document.body[p] == "\\begin_inset Argument":
1308                         actualargs += 1
1309                 if actualargs == 1:
1310                     allowed_opts = 0
1311                     first_req = 2
1312         # Collect all arguments in this paragraph
1313         argnr = 0
1314         for p in range(parbeg, parend):
1315             if document.body[p] == "\\begin_inset Argument":
1316                 argnr += 1
1317                 if allowed_opts != -1:
1318                     # We have less arguments than opt + required.
1319                     # required must take precedence.
1320                     if argnr > allowed_opts and argnr < first_req:
1321                         argnr = first_req
1322                 document.body[p] = "\\begin_inset Argument %d" % argnr
1323         i = i + 1
1324
1325
1326 def revert_latexargs(document):
1327     " Revert InsetArgument to old syntax "
1328
1329     i = 0
1330     rx = re.compile(r'^\\begin_inset Argument (\d+)$')
1331     args = dict()
1332     while True:
1333         # Search for Argument insets
1334         i = find_token(document.body, "\\begin_inset Argument", i)
1335         if i == -1:
1336             return
1337         m = rx.match(document.body[i])
1338         if not m:
1339             # No ID: inset already reverted
1340             i = i + 1
1341             continue
1342         # Find containing paragraph layout
1343         parent = get_containing_layout(document.body, i)
1344         if parent == False:
1345             document.warning("Malformed lyx document: Can't find parent paragraph layout")
1346             i = i + 1
1347             continue
1348         parbeg = parent[1]
1349         parend = parent[2]
1350         realparbeg = parent[3]
1351         # Collect all arguments in this paragraph 
1352         realparend = parend
1353         for p in range(parbeg, parend):
1354             m = rx.match(document.body[p])
1355             if m:
1356                 val = int(m.group(1))
1357                 j = find_end_of_inset(document.body, p)
1358                 # Revert to old syntax
1359                 document.body[p] = "\\begin_inset Argument"
1360                 if j == -1:
1361                     document.warning("Malformed lyx document: Can't find end of Argument inset")
1362                     continue
1363                 if val > 0:
1364                     args[val] = document.body[p : j + 1]
1365                 # Adjust range end
1366                 realparend = realparend - len(document.body[p : j + 1])
1367                 # Remove arg inset at this position
1368                 del document.body[p : j + 1]
1369             if p >= realparend:
1370                 break
1371         # Now sort the arg insets
1372         subst = [""]
1373         for f in sorted(args):
1374             subst += args[f]
1375             del args[f]
1376         # Insert the sorted arg insets at paragraph begin
1377         document.body[realparbeg : realparbeg] = subst
1378
1379         i = realparbeg + 1 + len(subst)
1380
1381
1382 def revert_Argument_to_TeX_brace(document, line, n, nmax, environment):
1383     '''
1384     Reverts an InsetArgument to TeX-code
1385     usage:
1386     revert_Argument_to_TeX_brace(document, LineOfBeginLayout, StartArgument, EndArgument, isEnvironment)
1387     LineOfBeginLayout is the line  of the \begin_layout statement
1388     StartArgument is the number of the first argument that needs to be converted
1389     EndArgument is the number of the last argument that needs to be converted or the last defined one
1390     isEnvironment must be true, if the layout id for a LaTeX environment
1391     '''
1392     lineArg = 0
1393     while lineArg != -1 and n < nmax + 1:
1394       lineArg = find_token(document.body, "\\begin_inset Argument " + str(n), line)
1395       if lineArg != -1:
1396         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
1397         # we have to assure that no other inset is in the Argument
1398         beginInset = find_token(document.body, "\\begin_inset", beginPlain)
1399         endInset = find_token(document.body, "\\end_inset", beginPlain)
1400         k = beginPlain + 1
1401         l = k
1402         while beginInset < endInset and beginInset != -1:
1403           beginInset = find_token(document.body, "\\begin_inset", k)
1404           endInset = find_token(document.body, "\\end_inset", l)
1405           k = beginInset + 1
1406           l = endInset + 1
1407         if environment == False:
1408           document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}{")
1409           del(document.body[lineArg : beginPlain + 1])
1410         else:
1411           document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}")
1412           document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("{")
1413         n = n + 1
1414
1415
1416 def revert_IEEEtran(document):
1417   '''
1418   Reverts InsetArgument of
1419   Page headings
1420   Biography
1421   Biography without photo
1422   to TeX-code
1423   '''
1424   if document.textclass == "IEEEtran":
1425     i = 0
1426     j = 0
1427     k = 0
1428     while True:
1429       if i != -1:
1430         i = find_token(document.body, "\\begin_layout Page headings", i)
1431       if i != -1:
1432         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1433         i = i + 1
1434       if j != -1:
1435         j = find_token(document.body, "\\begin_layout Biography without photo", j)
1436       if j != -1:
1437         revert_Argument_to_TeX_brace(document, j, 1, 1, True)
1438         j = j + 1
1439       if k != -1:
1440         k = find_token(document.body, "\\begin_layout Biography", k)
1441         kA = find_token(document.body, "\\begin_layout Biography without photo", k)
1442         if k == kA and k != -1:
1443           k = k + 1
1444           continue
1445       if k != -1:
1446         # start with the second argument, therefore 2
1447         revert_Argument_to_TeX_brace(document, k, 2, 2, True)
1448         k = k + 1
1449       if i == -1 and j == -1 and k == -1:
1450         return
1451
1452
1453 def convert_TeX_brace_to_Argument(document, line, n, nmax, inset, environment):
1454     '''
1455     Converts TeX code for mandatory arguments to an InsetArgument
1456     The conversion of TeX code for optional arguments must be done with another routine
1457     !!! Be careful if the braces are different in your case as expected here:
1458     - "}{" separates mandatory arguments of commands
1459     - "}" + "{" separates mandatory arguments of commands
1460     - "}" + " " + "{" separates mandatory arguments of commands
1461     - { and } surround a mandatory argument of an environment
1462     usage:
1463     convert_TeX_brace_to_Argument(document, LineOfBeginLayout/Inset, StartArgument, EndArgument, isInset, isEnvironment)
1464     LineOfBeginLayout/Inset is the line  of the \begin_layout or \begin_inset statement
1465     StartArgument is the number of the first ERT that needs to be converted
1466     EndArgument is the number of the last ERT that needs to be converted
1467     isInset must be true, if braces inside an InsetLayout needs to be converted
1468     isEnvironment must be true, if the layout is for a LaTeX environment
1469     
1470     Todo: this routine can currently handle only one mandatory argument of environments
1471     '''
1472     lineERT = line
1473     endn = line
1474     loop = 1
1475     while lineERT != -1 and n < nmax + 1:
1476       lineERT = find_token(document.body, "\\begin_inset ERT", lineERT)
1477       if environment == False and lineERT != -1:
1478         bracePair = find_token(document.body, "}{", lineERT)
1479         # assure that the "}{" is in this ERT
1480         if bracePair == lineERT + 5:
1481           end = find_token(document.body, "\\end_inset", bracePair)
1482           document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
1483           if loop == 1:
1484             # in the case that n > 1 we have optional arguments before
1485             # therefore detect them if any
1486             if n > 1:
1487               # first check if there is an argument
1488               lineArg = find_token(document.body, "\\begin_inset Argument", line)
1489               if lineArg < lineERT and lineArg != -1:
1490                 # we have an argument, so now search backwards for its end
1491                 # we must now assure that we don't find other insets like e.g. a newline
1492                 endInsetArg = lineERT
1493                 endLayoutArg = endInsetArg
1494                 while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
1495                   endInsetArg = endInsetArg - 1
1496                   endLayoutArg = endInsetArg
1497                   endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
1498                   endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
1499                 line = endInsetArg + 1
1500             if inset == False:
1501               document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1502             else:
1503               document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1504           else:
1505             document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1506           n = n + 1
1507           endn = end
1508           loop = loop + 1
1509         # now check the case that we have "}" + "{" in two ERTs
1510         else:
1511           endBrace = find_token(document.body, "}", lineERT)
1512           if endBrace == lineERT + 5:
1513             beginBrace = find_token(document.body, "{", endBrace)
1514             # assure that the ERTs are consecutive (11 or 12 depending if there is a space between the ERTs or not)
1515             if beginBrace == endBrace + 11 or beginBrace == endBrace + 12:
1516               end = find_token(document.body, "\\end_inset", beginBrace)
1517               document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
1518               if loop == 1:
1519                 # in the case that n > 1 we have optional arguments before
1520                 # therefore detect them if any
1521                 if n > 1:
1522                   # first check if there is an argument
1523                   lineArg = find_token(document.body, "\\begin_inset Argument", line)
1524                   if lineArg < lineERT and lineArg != -1:
1525                     # we have an argument, so now search backwards for its end
1526                     # we must now assure that we don't find other insets like e.g. a newline
1527                     endInsetArg = lineERT
1528                     endLayoutArg = endInsetArg
1529                     while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
1530                       endInsetArg = endInsetArg - 1
1531                       endLayoutArg = endInsetArg
1532                       endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
1533                       endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
1534                     line = endInsetArg + 1
1535                 if inset == False:
1536                   document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1537                 else:
1538                   document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1539               else:
1540                 document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1541               n = n + 1
1542               loop = loop + 1
1543               # set the line where the next argument will be inserted
1544               if beginBrace == endBrace + 11:
1545                 endn = end - 11
1546               else:
1547                 endn = end - 12
1548           else:
1549             lineERT = lineERT + 1
1550       if environment == True and lineERT != -1:
1551         opening = find_token(document.body, "{", lineERT)
1552         if opening == lineERT + 5: # assure that the "{" is in this ERT
1553           end = find_token(document.body, "\\end_inset", opening)
1554           document.body[lineERT : end + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
1555           n = n + 1
1556           lineERT2 = find_token(document.body, "\\begin_inset ERT", lineERT)
1557           closing = find_token(document.body, "}", lineERT2)
1558           if closing == lineERT2 + 5: # assure that the "}" is in this ERT
1559             end2 = find_token(document.body, "\\end_inset", closing)
1560             document.body[lineERT2 : end2 + 1] = ["\\end_layout", "", "\\end_inset"]
1561         else:
1562           lineERT = lineERT + 1
1563
1564
1565 def convert_IEEEtran(document):
1566   '''
1567   Converts ERT of
1568   Page headings
1569   Biography
1570   Biography without photo
1571   to InsetArgument
1572   '''
1573   if document.textclass == "IEEEtran":
1574     i = 0
1575     j = 0
1576     k = 0
1577     while True:
1578       if i != -1:
1579         i = find_token(document.body, "\\begin_layout Page headings", i)
1580       if i != -1:
1581         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1582         i = i + 1
1583       if j != -1:
1584         j = find_token(document.body, "\\begin_layout Biography without photo", j)
1585       if j != -1:
1586         convert_TeX_brace_to_Argument(document, j, 1, 1, False, True)
1587         j = j + 1
1588       if k != -1:
1589         # assure that we don't handle Biography Biography without photo
1590         k = find_token(document.body, "\\begin_layout Biography", k)
1591         kA = find_token(document.body, "\\begin_layout Biography without photo", k - 1)
1592       if k == kA and k != -1:
1593         k = k + 1
1594         continue
1595       if k != -1:
1596         # the argument we want to convert is the second one
1597         convert_TeX_brace_to_Argument(document, k, 2, 2, False, True)
1598         k = k + 1
1599       if i == -1 and j == -1 and k == -1:
1600         return
1601
1602
1603 def revert_AASTeX(document):
1604   " Reverts InsetArgument of Altaffilation to TeX-code "
1605   if document.textclass == "aastex":
1606     i = 0
1607     while True:
1608       if i != -1:
1609         i = find_token(document.body, "\\begin_layout Altaffilation", i)
1610       if i != -1:
1611         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1612         i = i + 1
1613       if i == -1:
1614         return
1615
1616
1617 def convert_AASTeX(document):
1618   " Converts ERT of Altaffilation to InsetArgument "
1619   if document.textclass == "aastex":
1620     i = 0
1621     while True:
1622       if i != -1:
1623         i = find_token(document.body, "\\begin_layout Altaffilation", i)
1624       if i != -1:
1625         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1626         i = i + 1
1627       if i == -1:
1628         return
1629
1630
1631 def revert_AGUTeX(document):
1632   " Reverts InsetArgument of Author affiliation to TeX-code "
1633   if document.textclass == "agutex":
1634     i = 0
1635     while True:
1636       if i != -1:
1637         i = find_token(document.body, "\\begin_layout Author affiliation", i)
1638       if i != -1:
1639         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1640         i = i + 1
1641       if i == -1:
1642         return
1643
1644
1645 def convert_AGUTeX(document):
1646   " Converts ERT of Author affiliation to InsetArgument "
1647   if document.textclass == "agutex":
1648     i = 0
1649     while True:
1650       if i != -1:
1651         i = find_token(document.body, "\\begin_layout Author affiliation", i)
1652       if i != -1:
1653         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1654         i = i + 1
1655       if i == -1:
1656         return
1657
1658
1659 def revert_IJMP(document):
1660   " Reverts InsetArgument of MarkBoth to TeX-code "
1661   if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1662     i = 0
1663     while True:
1664       if i != -1:
1665         i = find_token(document.body, "\\begin_layout MarkBoth", i)
1666       if i != -1:
1667         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1668         i = i + 1
1669       if i == -1:
1670         return
1671
1672
1673 def convert_IJMP(document):
1674   " Converts ERT of MarkBoth to InsetArgument "
1675   if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1676     i = 0
1677     while True:
1678       if i != -1:
1679         i = find_token(document.body, "\\begin_layout MarkBoth", i)
1680       if i != -1:
1681         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1682         i = i + 1
1683       if i == -1:
1684         return
1685
1686
1687 def revert_SIGPLAN(document):
1688   " Reverts InsetArgument of MarkBoth to TeX-code "
1689   if document.textclass == "sigplanconf":
1690     i = 0
1691     j = 0
1692     while True:
1693       if i != -1:
1694         i = find_token(document.body, "\\begin_layout Conference", i)
1695       if i != -1:
1696         revert_Argument_to_TeX_brace(document, i, 1, 1, False)
1697         i = i + 1
1698       if j != -1:
1699         j = find_token(document.body, "\\begin_layout Author", j)
1700       if j != -1:
1701         revert_Argument_to_TeX_brace(document, j, 1, 2, False)
1702         j = j + 1
1703       if i == -1 and j == -1:
1704         return
1705
1706
1707 def convert_SIGPLAN(document):
1708   " Converts ERT of MarkBoth to InsetArgument "
1709   if document.textclass == "sigplanconf":
1710     i = 0
1711     j = 0
1712     while True:
1713       if i != -1:
1714         i = find_token(document.body, "\\begin_layout Conference", i)
1715       if i != -1:
1716         convert_TeX_brace_to_Argument(document, i, 1, 1, False, False)
1717         i = i + 1
1718       if j != -1:
1719         j = find_token(document.body, "\\begin_layout Author", j)
1720       if j != -1:
1721         convert_TeX_brace_to_Argument(document, j, 1, 2, False, False)
1722         j = j + 1
1723       if i == -1 and j == -1:
1724         return
1725
1726
1727 def revert_SIGGRAPH(document):
1728   " Reverts InsetArgument of Flex CRcat to TeX-code "
1729   if document.textclass == "acmsiggraph":
1730     i = 0
1731     while True:
1732       if i != -1:
1733         i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1734       if i != -1:
1735         revert_Argument_to_TeX_brace(document, i, 1, 3, False)
1736         i = i + 1
1737       if i == -1:
1738         return
1739
1740
1741 def convert_SIGGRAPH(document):
1742   " Converts ERT of Flex CRcat to InsetArgument "
1743   if document.textclass == "acmsiggraph":
1744     i = 0
1745     while True:
1746       if i != -1:
1747         i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1748       if i != -1:
1749         convert_TeX_brace_to_Argument(document, i, 1, 3, True, False)
1750         i = i + 1
1751       if i == -1:
1752         return
1753
1754
1755 def revert_EuropeCV(document):
1756   " Reverts InsetArgument of Flex CRcat to TeX-code "
1757   if document.textclass == "europecv":
1758     i = 0
1759     j = 0
1760     k = 0
1761     m = 0
1762     while True:
1763       if i != -1:
1764         i = find_token(document.body, "\\begin_layout Item", i)
1765       if i != -1:
1766         revert_Argument_to_TeX_brace(document, i, 2, 2, False)
1767         i = i + 1
1768       if j != -1:
1769         j = find_token(document.body, "\\begin_layout BulletedItem", j)
1770       if j != -1:
1771         revert_Argument_to_TeX_brace(document, j, 2, 2, False)
1772         j = j + 1
1773       if k != -1:
1774         k = find_token(document.body, "\\begin_layout Language", k)
1775       if k != -1:
1776         revert_Argument_to_TeX_brace(document, k, 2, 6, False)
1777         k = k + 1
1778       if m != -1:
1779         m = find_token(document.body, "\\begin_layout LastLanguage", m)
1780       if m != -1:
1781         revert_Argument_to_TeX_brace(document, m, 2, 6, False)
1782         m = m + 1
1783       if i == -1 and j == -1 and k == -1 and m == -1:
1784         return
1785
1786
1787 def convert_EuropeCV(document):
1788   " Converts ERT of Flex CRcat to InsetArgument "
1789   if document.textclass == "europecv":
1790     i = 0
1791     j = 0
1792     k = 0
1793     m = 0
1794     while True:
1795       if i != -1:
1796         i = find_token(document.body, "\\begin_layout Item", i)
1797       if i != -1:
1798         convert_TeX_brace_to_Argument(document, i, 2, 2, False, False)
1799         i = i + 1
1800       if j != -1:
1801         j = find_token(document.body, "\\begin_layout BulletedItem", j)
1802       if j != -1:
1803         convert_TeX_brace_to_Argument(document, j, 2, 2, False, False)
1804         j = j + 1
1805       if k != -1:
1806         k = find_token(document.body, "\\begin_layout Language", k)
1807       if k != -1:
1808         convert_TeX_brace_to_Argument(document, k, 2, 6, False, False)
1809         k = k + 1
1810       if m != -1:
1811         m = find_token(document.body, "\\begin_layout LastLanguage", m)
1812       if m != -1:
1813         convert_TeX_brace_to_Argument(document, m, 2, 6, False, False)
1814         m = m + 1
1815       if i == -1 and j == -1 and k == -1 and m == -1:
1816         return
1817
1818
1819 def revert_literate(document):
1820     " Revert Literate document to old format "
1821     if del_token(document.header, "noweb", 0):
1822       document.textclass = "literate-" + document.textclass
1823       i = 0
1824       while True:
1825         i = find_token(document.body, "\\begin_layout Chunk", i)
1826         if i == -1:
1827           break
1828         document.body[i] = "\\begin_layout Scrap"
1829         i = i + 1
1830
1831
1832 def convert_literate(document):
1833     " Convert Literate document to new format"
1834     i = find_token(document.header, "\\textclass", 0)    
1835     if (i != -1) and "literate-" in document.header[i]:
1836       document.textclass = document.header[i].replace("\\textclass literate-", "")
1837       j = find_token(document.header, "\\begin_modules", 0)
1838       if (j != -1):
1839         document.header.insert(j + 1, "noweb")
1840       else:
1841         document.header.insert(i + 1, "\\end_modules")
1842         document.header.insert(i + 1, "noweb")
1843         document.header.insert(i + 1, "\\begin_modules")
1844       i = 0
1845       while True:
1846         i = find_token(document.body, "\\begin_layout Scrap", i)
1847         if i == -1:
1848           break
1849         document.body[i] = "\\begin_layout Chunk"
1850         i = i + 1
1851
1852
1853 def revert_itemargs(document):
1854     " Reverts \\item arguments to TeX-code "
1855     i = 0
1856     while True:
1857         i = find_token(document.body, "\\begin_inset Argument item:", i)
1858         if i == -1:
1859             return
1860         j = find_end_of_inset(document.body, i)
1861         # Find containing paragraph layout
1862         parent = get_containing_layout(document.body, i)
1863         if parent == False:
1864             document.warning("Malformed lyx document: Can't find parent paragraph layout")
1865             i = i + 1
1866             continue
1867         parbeg = parent[3]
1868         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
1869         endPlain = find_end_of_layout(document.body, beginPlain)
1870         content = document.body[beginPlain + 1 : endPlain]
1871         del document.body[i:j+1]
1872         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
1873         document.body[parbeg : parbeg] = subst
1874         i = i + 1
1875
1876
1877 def revert_garamondx_newtxmath(document):
1878     " Revert native garamond newtxmath definition to LaTeX " 
1879
1880     i = find_token(document.header, "\\font_math", 0)
1881     if i == -1:
1882        return
1883     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1884         val = get_value(document.header, "\\font_math", i)
1885         if val == "garamondx-ntxm":
1886             add_to_preamble(document, "\\usepackage[garamondx]{newtxmath}")
1887             document.header[i] = "\\font_math auto"
1888
1889
1890 def revert_garamondx(document):
1891     " Revert native garamond font definition to LaTeX " 
1892
1893     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: 
1894         i = find_token(document.header, "\\font_roman garamondx", 0)
1895         if i != -1:
1896             osf = False
1897             j = find_token(document.header, "\\font_osf true", 0)
1898             if j != -1:
1899                 osf = True
1900             preamble = "\\usepackage"
1901             if osf:
1902                 preamble += "[osfI]"
1903             preamble += "{garamondx}"
1904             add_to_preamble(document, [preamble])
1905             document.header[i] = "\\font_roman default"
1906
1907
1908 def convert_beamerargs(document):
1909     " Converts beamer arguments to new layout "
1910     
1911     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
1912     if document.textclass not in beamer_classes:
1913         return
1914
1915     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
1916     list_layouts = ["Itemize", "Enumerate", "Description"]
1917     rx = re.compile(r'^\\begin_inset Argument (\d+)$')
1918
1919     i = 0
1920     while True:
1921         i = find_token(document.body, "\\begin_inset Argument", i)
1922         if i == -1:
1923             return
1924         # Find containing paragraph layout
1925         parent = get_containing_layout(document.body, i)
1926         if parent == False:
1927             document.warning("Malformed lyx document: Can't find parent paragraph layout")
1928             i = i + 1
1929             continue
1930         parbeg = parent[1]
1931         parend = parent[2]
1932         layoutname = parent[0]
1933         for p in range(parbeg, parend):
1934             if layoutname in shifted_layouts:
1935                 m = rx.match(document.body[p])
1936                 if m:
1937                     argnr = int(m.group(1))
1938                     argnr += 1
1939                     document.body[p] = "\\begin_inset Argument %d" % argnr
1940             if layoutname == "AgainFrame":
1941                 m = rx.match(document.body[p])
1942                 if m:
1943                     document.body[p] = "\\begin_inset Argument 3"
1944                     if document.body[p + 4] == "\\begin_inset ERT":
1945                         if document.body[p + 9].startswith("<"):
1946                             # This is an overlay specification
1947                             # strip off the <
1948                             document.body[p + 9] = document.body[p + 9][1:]
1949                             if document.body[p + 9].endswith(">"):
1950                                 # strip off the >
1951                                 document.body[p + 9] = document.body[p + 9][:-1]
1952                                 # Shift this one
1953                                 document.body[p] = "\\begin_inset Argument 2"
1954             if layoutname in list_layouts:
1955                 m = rx.match(document.body[p])
1956                 if m:
1957                     if m.group(1) == "1":
1958                         if document.body[p + 4] == "\\begin_inset ERT":
1959                             if document.body[p + 9].startswith("<"):
1960                                 # This is an overlay specification
1961                                 # strip off the <
1962                                 document.body[p + 9] = document.body[p + 9][1:]
1963                                 if document.body[p + 9].endswith(">"):
1964                                     # strip off the >
1965                                     document.body[p + 9] = document.body[p + 9][:-1]
1966                         elif layoutname != "Itemize":
1967                             # Shift this one
1968                             document.body[p] = "\\begin_inset Argument 2"
1969         i = i + 1
1970
1971
1972 def convert_againframe_args(document):
1973     " Converts beamer AgainFrame to new layout "
1974
1975     # FIXME: This currently only works if the arguments are in one single ERT
1976     
1977     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
1978     if document.textclass not in beamer_classes:
1979         return
1980    
1981     i = 0
1982     while True:
1983         i = find_token(document.body, "\\begin_layout AgainFrame", i)
1984         if i == -1:
1985             break
1986         parent = get_containing_layout(document.body, i)
1987         if parent[1] != i:
1988             document.warning("Wrong parent layout!")
1989         j = parent[2]
1990         parbeg = parent[3]
1991         if i != -1:
1992             if document.body[parbeg] == "\\begin_inset ERT":
1993                 ertcont = parbeg + 5
1994                 if document.body[ertcont].startswith("[<"):
1995                     # This is a default overlay specification
1996                     # strip off the [<
1997                     document.body[ertcont] = document.body[ertcont][2:]
1998                     if document.body[ertcont].endswith(">]"):
1999                         # strip off the >]
2000                         document.body[ertcont] = document.body[ertcont][:-2]
2001                     elif document.body[ertcont].endswith("]"):
2002                         # divide the args
2003                         tok = document.body[ertcont].find('>][')
2004                         if tok != -1:
2005                             subst = [document.body[ertcont][:tok],
2006                                      '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2007                                      'status collapsed', '', '\\begin_layout Plain Layout',
2008                                      document.body[ertcont][tok + 3:-1]]
2009                             document.body[ertcont : ertcont + 1] = subst
2010                      # Convert to ArgInset
2011                     document.body[parbeg] = "\\begin_inset Argument 2"
2012                     i = j
2013                     continue
2014                 elif document.body[ertcont].startswith("<"):
2015                     # This is an overlay specification
2016                     # strip off the <
2017                     document.body[ertcont] = document.body[ertcont][1:]
2018                     if document.body[ertcont].endswith(">"):
2019                         # strip off the >
2020                         document.body[ertcont] = document.body[ertcont][:-1]
2021                         # Convert to ArgInset
2022                         document.body[parbeg] = "\\begin_inset Argument 1"
2023                     elif document.body[ertcont].endswith(">]"):
2024                         # divide the args
2025                         tok = document.body[ertcont].find('>[<')
2026                         if tok != -1:
2027                            document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2028                                                            '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2029                                                            'status collapsed', '', '\\begin_layout Plain Layout',
2030                                                            document.body[ertcont][tok + 3:-2]]
2031                         # Convert to ArgInset
2032                         document.body[parbeg] = "\\begin_inset Argument 1"
2033                     elif document.body[ertcont].endswith("]"):
2034                         # divide the args
2035                         tok = document.body[ertcont].find('>[<')
2036                         if tok != -1:
2037                            # divide the args
2038                            tokk = document.body[ertcont].find('>][')
2039                            if tokk != -1:
2040                                document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2041                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2042                                                                'status collapsed', '', '\\begin_layout Plain Layout',
2043                                                                document.body[ertcont][tok + 3:tokk],
2044                                                                '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2045                                                                'status collapsed', '', '\\begin_layout Plain Layout',
2046                                                                document.body[ertcont][tokk + 3:-1]]
2047                         else:
2048                             tokk = document.body[ertcont].find('>[')
2049                             if tokk != -1:
2050                                 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tokk],
2051                                                                 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2052                                                                 'status collapsed', '', '\\begin_layout Plain Layout',
2053                                                                 document.body[ertcont][tokk + 2:-1]]
2054                         # Convert to ArgInset
2055                         document.body[parbeg] = "\\begin_inset Argument 1"
2056                     i = j
2057                     continue
2058                 elif document.body[ertcont].startswith("["):
2059                     # This is an ERT option
2060                     # strip off the [
2061                     document.body[ertcont] = document.body[ertcont][1:]
2062                     if document.body[ertcont].endswith("]"):
2063                         # strip off the ]
2064                         document.body[ertcont] = document.body[ertcont][:-1]
2065                         # Convert to ArgInset
2066                         document.body[parbeg] = "\\begin_inset Argument 3"
2067                     i = j
2068                     continue
2069         i = j
2070
2071
2072 def convert_corollary_args(document):
2073     " Converts beamer corrolary-style ERT arguments native InsetArgs "
2074     
2075     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2076     if document.textclass not in beamer_classes:
2077         return
2078    
2079     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2080     for lay in corollary_layouts:
2081         i = 0
2082         while True:
2083             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2084             if i == -1:
2085                 break
2086             parent = get_containing_layout(document.body, i)
2087             if parent[1] != i:
2088                 document.warning("Wrong parent layout!")
2089             j = parent[2]
2090             parbeg = parent[3]
2091             if i != -1:
2092                 if document.body[parbeg] == "\\begin_inset ERT":
2093                     ertcont = parbeg + 5
2094                     if document.body[ertcont].startswith("<"):
2095                         # This is an overlay specification
2096                         # strip off the <
2097                         document.body[ertcont] = document.body[ertcont][1:]
2098                         if document.body[ertcont].endswith(">"):
2099                             # strip off the >
2100                             document.body[ertcont] = document.body[ertcont][:-1]
2101                         elif document.body[ertcont].endswith("]"):
2102                             # divide the args
2103                             tok = document.body[ertcont].find('>[')
2104                             if tok != -1:
2105                                 subst = [document.body[ertcont][:tok],
2106                                          '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2107                                          'status collapsed', '', '\\begin_layout Plain Layout',
2108                                          document.body[ertcont][tok + 2:-1]]
2109                                 document.body[ertcont : ertcont + 1] = subst
2110                         # Convert to ArgInset
2111                         document.body[parbeg] = "\\begin_inset Argument 1"
2112                         i = j
2113                         continue
2114                     elif document.body[ertcont].startswith("["):
2115                         # This is an ERT option
2116                         # strip off the [
2117                         document.body[ertcont] = document.body[ertcont][1:]
2118                         if document.body[ertcont].endswith("]"):
2119                             # strip off the ]
2120                             document.body[ertcont] = document.body[ertcont][:-1]
2121                         # Convert to ArgInset
2122                         document.body[parbeg] = "\\begin_inset Argument 2"
2123                     i = j
2124                     continue
2125             i = j
2126
2127
2128
2129 def convert_quote_args(document):
2130     " Converts beamer quote style ERT args to native InsetArgs "
2131     
2132     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2133     if document.textclass not in beamer_classes:
2134         return
2135    
2136     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2137     for lay in quote_layouts:
2138         i = 0
2139         while True:
2140             i = find_token(document.body, "\\begin_layout " + lay, i)
2141             if i == -1:
2142                 break
2143             parent = get_containing_layout(document.body, i)
2144             if parent[1] != i:
2145                 document.warning("Wrong parent layout!")
2146             j = parent[2]
2147             parbeg = parent[3]
2148             if i != -1:
2149                 if document.body[parbeg] == "\\begin_inset ERT":
2150                     if document.body[i + 6].startswith("<"):
2151                         # This is an overlay specification
2152                         # strip off the <
2153                         document.body[i + 6] = document.body[i + 6][1:]
2154                         if document.body[i + 6].endswith(">"):
2155                             # strip off the >
2156                             document.body[i + 6] = document.body[i + 6][:-1]
2157                             # Convert to ArgInset
2158                             document.body[i + 1] = "\\begin_inset Argument 1"
2159             i = j
2160
2161
2162 def revert_beamerargs(document):
2163     " Reverts beamer arguments to old layout "
2164     
2165     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2166     if document.textclass not in beamer_classes:
2167         return
2168
2169     i = 0
2170     list_layouts = ["Itemize", "Enumerate", "Description"]
2171     headings = ["Part", "Section", "Section*", "Subsection", "Subsection*",
2172                 "Subsubsection", "Subsubsection*", "FrameSubtitle", "NoteItem"]
2173     quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2174     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2175     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2176
2177     while True:
2178         i = find_token(document.body, "\\begin_inset Argument", i)
2179         if i == -1:
2180             return
2181         # Find containing paragraph layout
2182         parent = get_containing_layout(document.body, i)
2183         if parent == False:
2184             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2185             i = i + 1
2186             continue
2187         parbeg = parent[1]
2188         parend = parent[2]
2189         realparbeg = parent[3]
2190         layoutname = parent[0]
2191         realparend = parend
2192         for p in range(parbeg, parend):
2193             if p >= realparend:
2194                 i = realparend
2195                 break
2196             if layoutname in headings:
2197                 m = rx.match(document.body[p])
2198                 if m:
2199                     argnr = m.group(1)
2200                     if argnr == "1":
2201                         # Find containing paragraph layout
2202                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2203                         endPlain = find_end_of_layout(document.body, beginPlain)
2204                         endInset = find_end_of_inset(document.body, p)
2205                         argcontent = document.body[beginPlain + 1 : endPlain]
2206                         # Adjust range end
2207                         realparend = realparend - len(document.body[p : endInset + 1])
2208                         # Remove arg inset
2209                         del document.body[p : endInset + 1]
2210                         if layoutname == "FrameSubtitle":
2211                             pre = put_cmd_in_ert("\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2212                         elif layoutname == "NoteItem":
2213                             pre = put_cmd_in_ert("\\note<") + argcontent + put_cmd_in_ert(">[item]")
2214                         elif layoutname.endswith('*'):
2215                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower()[:-1] + "<") + argcontent + put_cmd_in_ert(">*")
2216                         else:
2217                             pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2218                         secarg = find_token(document.body, "\\begin_inset Argument 2", parbeg, parend)
2219                         if secarg != -1:
2220                             # Find containing paragraph layout
2221                             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", secarg)
2222                             endPlain = find_end_of_layout(document.body, beginPlain)
2223                             endInset = find_end_of_inset(document.body, secarg)
2224                             argcontent = document.body[beginPlain + 1 : endPlain]
2225                             # Adjust range end
2226                             realparend = realparend - len(document.body[secarg : endInset + 1])
2227                             del document.body[secarg : endInset + 1]
2228                             pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2229                         pre += put_cmd_in_ert("{")
2230                         document.body[parbeg] = "\\begin_layout Standard"
2231                         document.body[realparbeg : realparbeg] = pre
2232                         pe = find_end_of_layout(document.body, parbeg)
2233                         post = put_cmd_in_ert("}")
2234                         document.body[pe : pe] = post
2235                         realparend += len(pre) + len(post)
2236             if layoutname == "AgainFrame":
2237                 m = rx.match(document.body[p])
2238                 if m:
2239                     argnr = m.group(1)
2240                     if argnr == "3":
2241                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2242                         endPlain = find_end_of_layout(document.body, beginPlain)
2243                         endInset = find_end_of_inset(document.body, p)
2244                         content = document.body[beginPlain + 1 : endPlain]
2245                         # Adjust range end
2246                         realparend = realparend - len(document.body[p : endInset + 1])
2247                         # Remove arg inset
2248                         del document.body[p : endInset + 1]
2249                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2250                         document.body[realparbeg : realparbeg] = subst
2251             if layoutname == "Overprint":
2252                 m = rx.match(document.body[p])
2253                 if m:
2254                     argnr = m.group(1)
2255                     if argnr == "1":
2256                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2257                         endPlain = find_end_of_layout(document.body, beginPlain)
2258                         endInset = find_end_of_inset(document.body, p)
2259                         content = document.body[beginPlain + 1 : endPlain]
2260                         # Adjust range end
2261                         realparend = realparend - len(document.body[p : endInset + 1])
2262                         # Remove arg inset
2263                         del document.body[p : endInset + 1]
2264                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2265                         document.body[realparbeg : realparbeg] = subst
2266             if layoutname == "OverlayArea":
2267                 m = rx.match(document.body[p])
2268                 if m:
2269                     argnr = m.group(1)
2270                     if argnr == "2":
2271                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2272                         endPlain = find_end_of_layout(document.body, beginPlain)
2273                         endInset = find_end_of_inset(document.body, p)
2274                         content = document.body[beginPlain + 1 : endPlain]
2275                         # Adjust range end
2276                         realparend = realparend - len(document.body[p : endInset + 1])
2277                         # Remove arg inset
2278                         del document.body[p : endInset + 1]
2279                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2280                         document.body[realparbeg : realparbeg] = subst
2281             if layoutname in list_layouts:
2282                 m = rx.match(document.body[p])
2283                 if m:
2284                     argnr = m.group(1)
2285                     if argnr == "1":
2286                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2287                         endPlain = find_end_of_layout(document.body, beginPlain)
2288                         endInset = find_end_of_inset(document.body, p)
2289                         content = document.body[beginPlain + 1 : endPlain]
2290                         # Adjust range end
2291                         realparend = realparend - len(document.body[p : endInset + 1])
2292                         # Remove arg inset
2293                         del document.body[p : endInset + 1]
2294                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2295                         document.body[realparbeg : realparbeg] = subst
2296                     elif argnr == "item:1":
2297                         j = find_end_of_inset(document.body, i)
2298                         # Find containing paragraph layout
2299                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2300                         endPlain = find_end_of_layout(document.body, beginPlain)
2301                         content = document.body[beginPlain + 1 : endPlain]
2302                         del document.body[i:j+1]
2303                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2304                         document.body[realparbeg : realparbeg] = subst
2305                     elif argnr == "item:2":
2306                         j = find_end_of_inset(document.body, i)
2307                         # Find containing paragraph layout
2308                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2309                         endPlain = find_end_of_layout(document.body, beginPlain)
2310                         content = document.body[beginPlain + 1 : endPlain]
2311                         del document.body[i:j+1]
2312                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2313                         document.body[realparbeg : realparbeg] = subst
2314             if layoutname in quote_layouts:
2315                 m = rx.match(document.body[p])
2316                 if m:
2317                     argnr = m.group(1)
2318                     if argnr == "1":
2319                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2320                         endPlain = find_end_of_layout(document.body, beginPlain)
2321                         endInset = find_end_of_inset(document.body, p)
2322                         content = document.body[beginPlain + 1 : endPlain]
2323                         # Adjust range end
2324                         realparend = realparend - len(document.body[p : endInset + 1])
2325                         # Remove arg inset
2326                         del document.body[p : endInset + 1]
2327                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2328                         document.body[realparbeg : realparbeg] = subst
2329             if layoutname in corollary_layouts:
2330                 m = rx.match(document.body[p])
2331                 if m:
2332                     argnr = m.group(1)
2333                     if argnr == "2":
2334                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2335                         endPlain = find_end_of_layout(document.body, beginPlain)
2336                         endInset = find_end_of_inset(document.body, p)
2337                         content = document.body[beginPlain + 1 : endPlain]
2338                         # Adjust range end
2339                         realparend = realparend - len(document.body[p : endInset + 1])
2340                         # Remove arg inset
2341                         del document.body[p : endInset + 1]
2342                         subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2343                         document.body[realparbeg : realparbeg] = subst
2344         
2345         i = realparend
2346
2347
2348 def revert_beamerargs2(document):
2349     " Reverts beamer arguments to old layout, step 2 "
2350     
2351     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2352     if document.textclass not in beamer_classes:
2353         return
2354
2355     i = 0
2356     shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2357     corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2358     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2359
2360     while True:
2361         i = find_token(document.body, "\\begin_inset Argument", i)
2362         if i == -1:
2363             return
2364         # Find containing paragraph layout
2365         parent = get_containing_layout(document.body, i)
2366         if parent == False:
2367             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2368             i = i + 1
2369             continue
2370         parbeg = parent[1]
2371         parend = parent[2]
2372         realparbeg = parent[3]
2373         layoutname = parent[0]
2374         realparend = parend
2375         for p in range(parbeg, parend):
2376             if p >= realparend:
2377                 i = realparend
2378                 break
2379             if layoutname in shifted_layouts:
2380                 m = rx.match(document.body[p])
2381                 if m:
2382                     argnr = m.group(1)
2383                     if argnr == "2":
2384                         document.body[p] = "\\begin_inset Argument 1"       
2385             if layoutname in corollary_layouts:
2386                 m = rx.match(document.body[p])
2387                 if m:
2388                     argnr = m.group(1)
2389                     if argnr == "1":
2390                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2391                         endPlain = find_end_of_layout(document.body, beginPlain)
2392                         endInset = find_end_of_inset(document.body, p)
2393                         content = document.body[beginPlain + 1 : endPlain]
2394                         # Adjust range end
2395                         realparend = realparend - len(document.body[p : endInset + 1])
2396                         # Remove arg inset
2397                         del document.body[p : endInset + 1]
2398                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2399                         document.body[realparbeg : realparbeg] = subst
2400             if layoutname == "OverlayArea":
2401                 m = rx.match(document.body[p])
2402                 if m:
2403                     argnr = m.group(1)
2404                     if argnr == "1":
2405                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2406                         endPlain = find_end_of_layout(document.body, beginPlain)
2407                         endInset = find_end_of_inset(document.body, p)
2408                         content = document.body[beginPlain + 1 : endPlain]
2409                         # Adjust range end
2410                         realparend = realparend - len(document.body[p : endInset + 1])
2411                         # Remove arg inset
2412                         del document.body[p : endInset + 1]
2413                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2414                         document.body[realparbeg : realparbeg] = subst
2415             if layoutname == "AgainFrame":
2416                 m = rx.match(document.body[p])
2417                 if m:
2418                     argnr = m.group(1)
2419                     if argnr == "2":
2420                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2421                         endPlain = find_end_of_layout(document.body, beginPlain)
2422                         endInset = find_end_of_inset(document.body, p)
2423                         content = document.body[beginPlain + 1 : endPlain]
2424                         # Adjust range end
2425                         realparend = realparend - len(document.body[p : endInset + 1])
2426                         # Remove arg inset
2427                         del document.body[p : endInset + 1]
2428                         subst = put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
2429                         document.body[realparbeg : realparbeg] = subst
2430         i = realparend
2431
2432
2433 def revert_beamerargs3(document):
2434     " Reverts beamer arguments to old layout, step 3 "
2435     
2436     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2437     if document.textclass not in beamer_classes:
2438         return
2439
2440     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2441     i = 0
2442     while True:
2443         i = find_token(document.body, "\\begin_inset Argument", i)
2444         if i == -1:
2445             return
2446         # Find containing paragraph layout
2447         parent = get_containing_layout(document.body, i)
2448         if parent == False:
2449             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2450             i = i + 1
2451             continue
2452         parbeg = parent[1]
2453         parend = parent[2]
2454         realparbeg = parent[3]
2455         layoutname = parent[0]
2456         realparend = parend
2457         for p in range(parbeg, parend):
2458             if p >= realparend:
2459                 i = realparend
2460                 break
2461             if layoutname == "AgainFrame":
2462                 m = rx.match(document.body[p])
2463                 if m:
2464                     argnr = m.group(1)
2465                     if argnr == "1":
2466                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2467                         endPlain = find_end_of_layout(document.body, beginPlain)
2468                         endInset = find_end_of_inset(document.body, p)
2469                         content = document.body[beginPlain + 1 : endPlain]
2470                         # Adjust range end
2471                         realparend = realparend - len(document.body[p : endInset + 1])
2472                         # Remove arg inset
2473                         del document.body[p : endInset + 1]
2474                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2475                         document.body[realparbeg : realparbeg] = subst
2476         i = realparend
2477
2478
2479 def revert_beamerflex(document):
2480     " Reverts beamer Flex insets "
2481     
2482     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2483     if document.textclass not in beamer_classes:
2484         return
2485
2486     new_flexes = {"Bold" : "\\textbf", "Emphasize" : "\\emph", "Only" : "\\only",
2487                   "Uncover" : "\\uncover", "Visible" : "\\visible",
2488                   "Invisible" : "\\invisible", "Alternative" : "\\alt",
2489                   "Beamer_Note" : "\\note"}
2490     old_flexes = {"Alert" : "\\alert", "Structure" : "\\structure"}
2491     rx = re.compile(r'^\\begin_inset Flex (.+)$')
2492
2493     i = 0
2494     while True:
2495         i = find_token(document.body, "\\begin_inset Flex", i)
2496         if i == -1:
2497             return
2498         m = rx.match(document.body[i])
2499         if m:
2500             flextype = m.group(1)
2501             z = find_end_of_inset(document.body, i)
2502             if z == -1:
2503                 document.warning("Can't find end of Flex " + flextype + " inset.")
2504                 i += 1
2505                 continue
2506             if flextype in new_flexes:
2507                 pre = put_cmd_in_ert(new_flexes[flextype])
2508                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2509                 if arg != -1:
2510                     argend = find_end_of_inset(document.body, arg)
2511                     if argend == -1:
2512                         document.warning("Can't find end of Argument!")
2513                         i += 1
2514                         continue
2515                     # Find containing paragraph layout
2516                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2517                     endPlain = find_end_of_layout(document.body, beginPlain)
2518                     argcontent = document.body[beginPlain + 1 : endPlain]
2519                     # Adjust range end
2520                     z = z - len(document.body[arg : argend + 1])
2521                     # Remove arg inset
2522                     del document.body[arg : argend + 1]
2523                     pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2524                 arg = find_token(document.body, "\\begin_inset Argument 2", i, z)
2525                 if arg != -1:
2526                     argend = find_end_of_inset(document.body, arg)
2527                     if argend == -1:
2528                         document.warning("Can't find end of Argument!")
2529                         i += 1
2530                         continue
2531                     # Find containing paragraph layout
2532                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2533                     endPlain = find_end_of_layout(document.body, beginPlain)
2534                     argcontent = document.body[beginPlain + 1 : endPlain]
2535                     # Adjust range end
2536                     z = z - len(document.body[arg : argend + 1])
2537                     # Remove arg inset
2538                     del document.body[arg : argend + 1]
2539                     pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2540                 pre += put_cmd_in_ert("{")
2541                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2542                 endPlain = find_end_of_layout(document.body, beginPlain)
2543                 # Adjust range end
2544                 z = z - len(document.body[i : beginPlain + 1])
2545                 z += len(pre)
2546                 document.body[i : beginPlain + 1] = pre
2547                 post = put_cmd_in_ert("}")
2548                 document.body[z - 2 : z + 1] = post
2549             elif flextype in old_flexes:
2550                 pre = put_cmd_in_ert(old_flexes[flextype])
2551                 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2552                 if arg == -1:
2553                     i += 1
2554                     continue
2555                 argend = find_end_of_inset(document.body, arg)
2556                 if argend == -1:
2557                     document.warning("Can't find end of Argument!")
2558                     i += 1
2559                     continue
2560                 # Find containing paragraph layout
2561                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2562                 endPlain = find_end_of_layout(document.body, beginPlain)
2563                 argcontent = document.body[beginPlain + 1 : endPlain]
2564                 # Adjust range end
2565                 z = z - len(document.body[arg : argend + 1])
2566                 # Remove arg inset
2567                 del document.body[arg : argend + 1]
2568                 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2569                 pre += put_cmd_in_ert("{")
2570                 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2571                 endPlain = find_end_of_layout(document.body, beginPlain)
2572                 # Adjust range end
2573                 z = z - len(document.body[i : beginPlain + 1])
2574                 z += len(pre)
2575                 document.body[i : beginPlain + 1] = pre
2576                 post = put_cmd_in_ert("}")
2577                 document.body[z - 2 : z + 1] = post
2578         
2579         i += 1
2580
2581
2582 def revert_beamerblocks(document):
2583     " Reverts beamer block arguments to ERT "
2584     
2585     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2586     if document.textclass not in beamer_classes:
2587         return
2588
2589     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2590
2591     rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2592     i = 0
2593     while True:
2594         i = find_token(document.body, "\\begin_inset Argument", i)
2595         if i == -1:
2596             return
2597         # Find containing paragraph layout
2598         parent = get_containing_layout(document.body, i)
2599         if parent == False:
2600             document.warning("Malformed lyx document: Can't find parent paragraph layout")
2601             i = i + 1
2602             continue
2603         parbeg = parent[1]
2604         parend = parent[2]
2605         realparbeg = parent[3]
2606         layoutname = parent[0]
2607         realparend = parend
2608         for p in range(parbeg, parend):
2609             if p >= realparend:
2610                 i = realparend
2611                 break
2612             if layoutname in blocks:
2613                 m = rx.match(document.body[p])
2614                 if m:
2615                     argnr = m.group(1)
2616                     if argnr == "1":
2617                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2618                         endPlain = find_end_of_layout(document.body, beginPlain)
2619                         endInset = find_end_of_inset(document.body, p)
2620                         content = document.body[beginPlain + 1 : endPlain]
2621                         # Adjust range end
2622                         realparend = realparend - len(document.body[p : endInset + 1])
2623                         # Remove arg inset
2624                         del document.body[p : endInset + 1]
2625                         subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2626                         document.body[realparbeg : realparbeg] = subst
2627                     elif argnr == "2":
2628                         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2629                         endPlain = find_end_of_layout(document.body, beginPlain)
2630                         endInset = find_end_of_inset(document.body, p)
2631                         content = document.body[beginPlain + 1 : endPlain]
2632                         # Adjust range end
2633                         realparend = realparend - len(document.body[p : endInset + 1])
2634                         # Remove arg inset
2635                         del document.body[p : endInset + 1]
2636                         subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2637                         document.body[realparbeg : realparbeg] = subst
2638         i = realparend
2639
2640
2641
2642 def convert_beamerblocks(document):
2643     " Converts beamer block ERT args to native InsetArgs "
2644     
2645     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2646     if document.textclass not in beamer_classes:
2647         return
2648    
2649     blocks = ["Block", "ExampleBlock", "AlertBlock"]
2650     for lay in blocks:
2651         i = 0
2652         while True:
2653             i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2654             if i == -1:
2655                 break
2656             parent = get_containing_layout(document.body, i)
2657             if parent == False or parent[1] != i:
2658                 document.warning("Wrong parent layout!")
2659                 i += 1
2660                 continue
2661             j = parent[2]
2662             parbeg = parent[3]
2663             if i != -1:
2664                 if document.body[parbeg] == "\\begin_inset ERT":
2665                     ertcont = parbeg + 5
2666                     while True:
2667                         if document.body[ertcont].startswith("<"):
2668                             # This is an overlay specification
2669                             # strip off the <
2670                             document.body[ertcont] = document.body[ertcont][1:]
2671                             if document.body[ertcont].endswith(">"):
2672                                 # strip off the >
2673                                 document.body[ertcont] = document.body[ertcont][:-1]
2674                                 # Convert to ArgInset
2675                                 document.body[parbeg] = "\\begin_inset Argument 1"
2676                             elif document.body[ertcont].endswith("}"):
2677                                 # divide the args
2678                                 tok = document.body[ertcont].find('>{')
2679                                 if tok != -1:
2680                                     document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2681                                                                             '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2682                                                                             'status collapsed', '', '\\begin_layout Plain Layout',
2683                                                                             document.body[ertcont][tok + 2:-1]]
2684                             # Convert to ArgInset
2685                             document.body[parbeg] = "\\begin_inset Argument 1"
2686                         elif document.body[ertcont].startswith("{"):
2687                             # This is the block title
2688                             if document.body[ertcont].endswith("}"):
2689                                 # strip off the braces
2690                                 document.body[ertcont] = document.body[ertcont][1:-1]
2691                                 # Convert to ArgInset
2692                                 document.body[parbeg] = "\\begin_inset Argument 2"
2693                             elif count_pars_in_inset(document.body, ertcont) > 1:
2694                                 # Multipar ERT. Skip this.
2695                                 break
2696                             else:
2697                                 convert_TeX_brace_to_Argument(document, i, 2, 2, False, True)
2698                         else:
2699                             break
2700                         j = find_end_of_layout(document.body, i)
2701                         if j == -1:
2702                             document.warning("end of layout not found!")
2703                         k = find_token(document.body, "\\begin_inset Argument", i, j)
2704                         if k == -1:
2705                             document.warning("InsetArgument not found!")
2706                             break
2707                         l = find_end_of_inset(document.body, k)
2708                         m = find_token(document.body, "\\begin_inset ERT", l, j)
2709                         if m == -1:
2710                             break
2711                         ertcont = m + 5
2712                         parbeg = m
2713             i = j
2714
2715
2716 def convert_overprint(document):
2717     " Convert old beamer overprint layouts to ERT "
2718     
2719     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2720     if document.textclass not in beamer_classes:
2721         return
2722
2723     i = 0
2724     while True:
2725         i = find_token(document.body, "\\begin_layout Overprint", i)
2726         if i == -1:
2727             return
2728         # Find end of sequence
2729         j = find_end_of_sequence(document.body, i)
2730         if j == -1:
2731             document.warning("Malformed lyx document. Cannot find end of Overprint sequence!")
2732             i = i + 1
2733             continue
2734         endseq = j
2735         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
2736         esubst = list()
2737         if document.body[j] == "\\end_deeper":
2738             esubst = ["", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
2739         else:
2740             esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
2741         endseq = endseq + len(esubst) - len(document.body[j : j])
2742         document.body[j : j] = esubst
2743         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
2744         if argbeg != -1:
2745             argend = find_end_of_layout(document.body, argbeg)
2746             if argend == -1:
2747                 document.warning("Malformed lyx document. Cannot find end of Overprint argument!")
2748                 i = i + 1
2749                 continue
2750             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
2751             endPlain = find_end_of_layout(document.body, beginPlain)
2752             content = document.body[beginPlain + 1 : endPlain]
2753             # Adjust range end
2754             endseq = endseq - len(document.body[argbeg : argend + 1])
2755             # Remove arg inset
2756             del document.body[argbeg : argend + 1]
2757             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2758             
2759         endseq = endseq - len(document.body[i : i])
2760         document.body[i : i] = subst + ["\\end_layout"]
2761         endseq += len(subst)
2762         
2763         for p in range(i, endseq):
2764             if document.body[p] == "\\begin_layout Overprint":
2765                 document.body[p] = "\\begin_layout Standard"
2766
2767         i = endseq
2768
2769
2770 def revert_overprint(document):
2771     " Revert old beamer overprint layouts to ERT "
2772     
2773     beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2774     if document.textclass not in beamer_classes:
2775         return
2776
2777     i = 0
2778     while True:
2779         i = find_token(document.body, "\\begin_layout Overprint", i)
2780         if i == -1:
2781             return
2782         # Find end of sequence
2783         j = find_end_of_sequence(document.body, i)
2784         if j == -1:
2785             document.warning("Malformed lyx document. Cannot find end of Overprint sequence!")
2786             i = i + 1
2787             continue
2788         endseq = j
2789         subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
2790         esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}")
2791         endseq = endseq + len(esubst) - len(document.body[j : j])
2792         document.body[j : j] = esubst
2793         argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
2794         if argbeg != -1:
2795             argend = find_end_of_inset(document.body, argbeg)
2796             if argend == -1:
2797                 document.warning("Malformed lyx document. Cannot find end of Overprint argument!")
2798                 i = i + 1
2799                 continue
2800             beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
2801             endPlain = find_end_of_layout(document.body, beginPlain)
2802             content = document.body[beginPlain + 1 : endPlain]
2803             # Adjust range end
2804             endseq = endseq - len(document.body[argbeg : argend])
2805             # Remove arg inset
2806             del document.body[argbeg : argend + 1]
2807             subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2808             
2809         endseq = endseq - len(document.body[i : i])
2810         document.body[i : i] = subst + ["\\end_layout"]
2811         endseq += len(subst)
2812      
2813         p = i
2814         while True:
2815             if p >= endseq:
2816                 break
2817             if document.body[p] == "\\begin_layout Overprint":
2818                 q = find_end_of_layout(document.body, p)
2819                 if q == -1:
2820                     document.warning("Malformed lyx document. Cannot find end of Overprint layout!")
2821                     p += 1
2822                     continue
2823                 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\onslide")
2824                 argbeg = find_token(document.body, "\\begin_inset Argument item:1", p, q)
2825                 if argbeg != -1:
2826                     argend = find_end_of_inset(document.body, argbeg)
2827                     if argend == -1:
2828                         document.warning("Malformed lyx document. Cannot find end of Overprint item argument!")
2829                         p += 1
2830                         continue
2831                     beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
2832                     endPlain = find_end_of_layout(document.body, beginPlain)
2833                     content = document.body[beginPlain + 1 : endPlain]
2834                     # Adjust range end
2835                     endseq = endseq - len(document.body[argbeg : argend + 1])
2836                     # Remove arg inset
2837                     del document.body[argbeg : argend + 1]
2838                     subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2839                 endseq = endseq - len(document.body[p : p + 1]) + len(subst)
2840                 document.body[p : p + 1] = subst
2841             p = p + 1
2842
2843         i = endseq
2844
2845
2846 ##
2847 # Conversion hub
2848 #
2849
2850 supported_versions = ["2.1.0","2.1"]
2851 convert = [
2852            [414, []],
2853            [415, [convert_undertilde]],
2854            [416, []],
2855            [417, [convert_japanese_encodings]],
2856            [418, []],
2857            [419, []],
2858            [420, [convert_biblio_style]],
2859            [421, [convert_longtable_captions]],
2860            [422, [convert_use_packages]],
2861            [423, [convert_use_mathtools]],
2862            [424, [convert_cite_engine_type]],
2863            [425, []],
2864            [426, []],
2865            [427, []],
2866            [428, [convert_cell_rotation]],
2867            [429, [convert_table_rotation]],
2868            [430, [convert_listoflistings]],
2869            [431, [convert_use_amssymb]],
2870            [432, []],
2871            [433, [convert_armenian]],
2872            [434, []],
2873            [435, []],
2874            [436, []],
2875            [437, []],
2876            [438, []],
2877            [439, []],
2878            [440, []],
2879            [441, [convert_mdnomath]],
2880            [442, []],
2881            [443, []],
2882            [444, []],
2883            [445, []],
2884            [446, [convert_latexargs]],
2885            [447, [convert_IEEEtran, convert_AASTeX, convert_AGUTeX, convert_IJMP, convert_SIGPLAN, convert_SIGGRAPH, convert_EuropeCV]],
2886            [448, [convert_literate]],
2887            [449, []],
2888            [450, []],
2889            [451, [convert_beamerargs, convert_againframe_args, convert_corollary_args, convert_quote_args]],
2890            [452, [convert_beamerblocks]],
2891            [453, [convert_use_stmaryrd]],
2892            [454, [convert_overprint]]
2893           ]
2894
2895 revert =  [
2896            [453, [revert_overprint]],
2897            [452, [revert_use_stmaryrd]],
2898            [451, [revert_beamerblocks]],
2899            [450, [revert_beamerargs, revert_beamerargs2, revert_beamerargs3, revert_beamerflex]],
2900            [449, [revert_garamondx, revert_garamondx_newtxmath]],
2901            [448, [revert_itemargs]],
2902            [447, [revert_literate]],
2903            [446, [revert_IEEEtran, revert_AASTeX, revert_AGUTeX, revert_IJMP, revert_SIGPLAN, revert_SIGGRAPH, revert_EuropeCV]],
2904            [445, [revert_latexargs]],
2905            [444, [revert_uop]],
2906            [443, [revert_biolinum]],
2907            [442, []],
2908            [441, [revert_newtxmath]],
2909            [440, [revert_mdnomath]],
2910            [439, [revert_mathfonts]],
2911            [438, [revert_minionpro]],
2912            [437, [revert_ipadeco, revert_ipachar]],
2913            [436, [revert_texgyre]],
2914            [435, [revert_mathdesign]],
2915            [434, [revert_txtt]],
2916            [433, [revert_libertine]],
2917            [432, [revert_armenian]],
2918            [431, [revert_languages, revert_ancientgreek]],
2919            [430, [revert_use_amssymb]],
2920            [429, [revert_listoflistings]],
2921            [428, [revert_table_rotation]],
2922            [427, [revert_cell_rotation]],
2923            [426, [revert_tipa]],
2924            [425, [revert_verbatim]],
2925            [424, [revert_cancel]],
2926            [423, [revert_cite_engine_type]],
2927            [422, [revert_use_mathtools]],
2928            [421, [revert_use_packages]],
2929            [420, [revert_longtable_captions]],
2930            [419, [revert_biblio_style]],
2931            [418, [revert_australian]],
2932            [417, [revert_justification]],
2933            [416, [revert_japanese_encodings]],
2934            [415, [revert_negative_space, revert_math_spaces]],
2935            [414, [revert_undertilde]],
2936            [413, [revert_visible_space]]
2937           ]
2938
2939
2940 if __name__ == "__main__":
2941     pass