]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_0.py
79f9f1be2f17c2fa826bf22c751038cbea3b0f8f
[lyx.git] / lib / lyx2lyx / lyx_2_0.py
1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # -*- coding: utf-8 -*-
4 # Copyright (C) 2010 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 """ Convert files to the file format generated by lyx 2.0"""
21
22 import re, string
23 import unicodedata
24 import sys, os
25
26 from parser_tools import find_token, find_end_of, find_tokens, \
27   find_end_of_inset, find_end_of_layout, find_token_backwards, \
28   get_containing_inset, get_value, get_value_string
29   
30 from lyx2lyx_tools import add_to_preamble, insert_to_preamble, \
31   put_cmd_in_ert, lyx2latex, latex_length, revert_flex_inset, \
32   revert_font_attrs, revert_layout_command, hex2ratio
33
34 ####################################################################
35 # Private helper functions
36
37 def remove_option(document, m, option):
38     ''' removes option from line m. returns whether we did anything '''
39     l = document.body[m].find(option)
40     if l == -1:
41         return False
42     val = document.body[m][l:].split('"')[1]
43     document.body[m] = document.body[m][:l - 1] + document.body[m][l+len(option + '="' + val + '"'):]
44     return True
45
46
47 # DO NOT USE THIS ROUTINE ANY MORE. Better yet, replace the uses that
48 # have been made of it with uses of put_cmd_in_ert.
49 def old_put_cmd_in_ert(string):
50     for rep in unicode_reps:
51         string = string.replace(rep[1], rep[0].replace('\\\\', '\\'))
52     string = string.replace('\\', "\\backslash\n")
53     string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Plain Layout\n" \
54       + string + "\n\\end_layout\n\\end_inset"
55     return string
56
57
58 ###############################################################################
59 ###
60 ### Conversion and reversion routines
61 ###
62 ###############################################################################
63
64 def revert_swiss(document):
65     " Set language german-ch to ngerman "
66     i = 0
67     if document.language == "german-ch":
68         document.language = "ngerman"
69         i = find_token(document.header, "\\language", 0)
70         if i != -1:
71             document.header[i] = "\\language ngerman"
72     j = 0
73     while True:
74         j = find_token(document.body, "\\lang german-ch", j)
75         if j == -1:
76             return
77         document.body[j] = document.body[j].replace("\\lang german-ch", "\\lang ngerman")
78         j = j + 1
79
80
81 def revert_tabularvalign(document):
82    " Revert the tabular valign option "
83    i = 0
84    while True:
85       i = find_token(document.body, "\\begin_inset Tabular", i)
86       if i == -1:
87           return
88       end = find_end_of_inset(document.body, i)
89       if end == -1:
90           document.warning("Can't find end of inset at line " + str(i))
91           i += 1
92           continue
93       fline = find_token(document.body, "<features", i, end)
94       if fline == -1:
95           document.warning("Can't find features for inset at line " + str(i))
96           i += 1
97           continue
98       p = document.body[fline].find("islongtable")
99       if p != -1:
100           q = document.body[fline].find("tabularvalignment")
101           if q != -1:
102               # FIXME
103               # This seems wrong: It removes everything after 
104               # tabularvalignment, too.
105               document.body[fline] = document.body[fline][:q - 1] + '>'
106           i += 1
107           continue
108
109        # no longtable
110       tabularvalignment = 'c'
111       # which valignment is specified?
112       m = document.body[fline].find('tabularvalignment="top"')
113       if m != -1:
114           tabularvalignment = 't'
115       m = document.body[fline].find('tabularvalignment="bottom"')
116       if m != -1:
117           tabularvalignment = 'b'
118       # delete tabularvalignment
119       q = document.body[fline].find("tabularvalignment")
120       if q != -1:
121           # FIXME
122           # This seems wrong: It removes everything after 
123           # tabularvalignment, too.
124           document.body[fline] = document.body[fline][:q - 1] + '>'
125
126       # don't add a box when centered
127       if tabularvalignment == 'c':
128           i = end
129           continue
130       subst = ['\\end_layout', '\\end_inset']
131       document.body[end:end] = subst # just inserts those lines
132       subst = ['\\begin_inset Box Frameless',
133           'position "' + tabularvalignment +'"',
134           'hor_pos "c"',
135           'has_inner_box 1',
136           'inner_pos "c"',
137           'use_parbox 0',
138           # we don't know the width, assume 50%
139           'width "50col%"',
140           'special "none"',
141           'height "1in"',
142           'height_special "totalheight"',
143           'status open',
144           '',
145           '\\begin_layout Plain Layout']
146       document.body[i:i] = subst # this just inserts the array at i
147       # since there could be a tabular inside a tabular, we cannot
148       # jump to end
149       i += len(subst)
150
151
152 def revert_phantom_types(document, ptype, cmd):
153     " Reverts phantom to ERT "
154     i = 0
155     while True:
156       i = find_token(document.body, "\\begin_inset Phantom " + ptype, i)
157       if i == -1:
158           return
159       end = find_end_of_inset(document.body, i)
160       if end == -1:
161           document.warning("Can't find end of inset at line " + str(i))
162           i += 1
163           continue
164       blay = find_token(document.body, "\\begin_layout Plain Layout", i, end)
165       if blay == -1:
166           document.warning("Can't find layout for inset at line " + str(i))
167           i = end
168           continue
169       bend = find_token(document.body, "\\end_layout", blay, end)
170       if bend == -1:
171           document.warning("Malformed LyX document: Could not find end of Phantom inset's layout.")
172           i = end
173           continue
174       substi = ["\\begin_inset ERT", "status collapsed", "",
175                 "\\begin_layout Plain Layout", "", "", "\\backslash", 
176                 cmd + "{", "\\end_layout", "", "\\end_inset"]
177       substj = ["\\size default", "", "\\begin_inset ERT", "status collapsed", "",
178                 "\\begin_layout Plain Layout", "", "}", "\\end_layout", "", "\\end_inset"]
179       # do the later one first so as not to mess up the numbering
180       document.body[bend:end + 1] = substj
181       document.body[i:blay + 1] = substi
182       i = end + len(substi) + len(substj) - (end - bend) - (blay - i) - 2
183
184
185 def revert_phantom(document):
186     revert_phantom_types(document, "Phantom", "phantom")
187     
188 def revert_hphantom(document):
189     revert_phantom_types(document, "HPhantom", "hphantom")
190
191 def revert_vphantom(document):
192     revert_phantom_types(document, "VPhantom", "vphantom")
193
194
195 def revert_xetex(document):
196     " Reverts documents that use XeTeX "
197     i = find_token(document.header, '\\use_xetex', 0)
198     if i == -1:
199         document.warning("Malformed LyX document: Missing \\use_xetex.")
200         return
201     if get_value(document.header, "\\use_xetex", i) == 'false':
202         del document.header[i]
203         return
204     del document.header[i]
205     # 1.) set doc encoding to utf8-plain
206     i = find_token(document.header, "\\inputencoding", 0)
207     if i == -1:
208         document.warning("Malformed LyX document: Missing \\inputencoding.")
209     document.header[i] = "\\inputencoding utf8-plain"
210     # 2.) check font settings
211     l = find_token(document.header, "\\font_roman", 0)
212     if l == -1:
213         document.warning("Malformed LyX document: Missing \\font_roman.")
214     line = document.header[l]
215     l = re.compile(r'\\font_roman (.*)$')
216     m = l.match(line)
217     roman = m.group(1)
218     l = find_token(document.header, "\\font_sans", 0)
219     if l == -1:
220         document.warning("Malformed LyX document: Missing \\font_sans.")
221     line = document.header[l]
222     l = re.compile(r'\\font_sans (.*)$')
223     m = l.match(line)
224     sans = m.group(1)
225     l = find_token(document.header, "\\font_typewriter", 0)
226     if l == -1:
227         document.warning("Malformed LyX document: Missing \\font_typewriter.")
228     line = document.header[l]
229     l = re.compile(r'\\font_typewriter (.*)$')
230     m = l.match(line)
231     typewriter = m.group(1)
232     osf = get_value(document.header, '\\font_osf', 0) == "true"
233     sf_scale = float(get_value(document.header, '\\font_sf_scale', 0))
234     tt_scale = float(get_value(document.header, '\\font_tt_scale', 0))
235     # 3.) set preamble stuff
236     pretext = '%% This document must be processed with xelatex!\n'
237     pretext += '\\usepackage{fontspec}\n'
238     if roman != "default":
239         pretext += '\\setmainfont[Mapping=tex-text]{' + roman + '}\n'
240     if sans != "default":
241         pretext += '\\setsansfont['
242         if sf_scale != 100:
243             pretext += 'Scale=' + str(sf_scale / 100) + ','
244         pretext += 'Mapping=tex-text]{' + sans + '}\n'
245     if typewriter != "default":
246         pretext += '\\setmonofont'
247         if tt_scale != 100:
248             pretext += '[Scale=' + str(tt_scale / 100) + ']'
249         pretext += '{' + typewriter + '}\n'
250     if osf:
251         pretext += '\\defaultfontfeatures{Numbers=OldStyle}\n'
252     pretext += '\usepackage{xunicode}\n'
253     pretext += '\usepackage{xltxtra}\n'
254     insert_to_preamble(0, document, pretext)
255     # 4.) reset font settings
256     i = find_token(document.header, "\\font_roman", 0)
257     if i == -1:
258         document.warning("Malformed LyX document: Missing \\font_roman.")
259     document.header[i] = "\\font_roman default"
260     i = find_token(document.header, "\\font_sans", 0)
261     if i == -1:
262         document.warning("Malformed LyX document: Missing \\font_sans.")
263     document.header[i] = "\\font_sans default"
264     i = find_token(document.header, "\\font_typewriter", 0)
265     if i == -1:
266         document.warning("Malformed LyX document: Missing \\font_typewriter.")
267     document.header[i] = "\\font_typewriter default"
268     i = find_token(document.header, "\\font_osf", 0)
269     if i == -1:
270         document.warning("Malformed LyX document: Missing \\font_osf.")
271     document.header[i] = "\\font_osf false"
272     i = find_token(document.header, "\\font_sc", 0)
273     if i == -1:
274         document.warning("Malformed LyX document: Missing \\font_sc.")
275     document.header[i] = "\\font_sc false"
276     i = find_token(document.header, "\\font_sf_scale", 0)
277     if i == -1:
278         document.warning("Malformed LyX document: Missing \\font_sf_scale.")
279     document.header[i] = "\\font_sf_scale 100"
280     i = find_token(document.header, "\\font_tt_scale", 0)
281     if i == -1:
282         document.warning("Malformed LyX document: Missing \\font_tt_scale.")
283     document.header[i] = "\\font_tt_scale 100"
284
285
286 def revert_outputformat(document):
287     " Remove default output format param "
288     i = find_token(document.header, '\\default_output_format', 0)
289     if i == -1:
290         document.warning("Malformed LyX document: Missing \\default_output_format.")
291         return
292     del document.header[i]
293
294
295 def revert_backgroundcolor(document):
296     " Reverts background color to preamble code "
297     i = find_token(document.header, "\\backgroundcolor", 0)
298     if i == -1:
299         return
300     colorcode = get_value(document.header, '\\backgroundcolor', i)
301     del document.header[i]
302     # don't clutter the preamble if backgroundcolor is not set
303     if colorcode == "#ffffff":
304         return
305     red   = hex2ratio(colorcode[1:3])
306     green = hex2ratio(colorcode[3:5])
307     blue  = hex2ratio(colorcode[5:7])
308     insert_to_preamble(0, document,
309                           '% Commands inserted by lyx2lyx to set the background color\n'
310                           + '\\@ifundefined{definecolor}{\\usepackage{color}}{}\n'
311                           + '\\definecolor{page_backgroundcolor}{rgb}{'
312                           + red + ',' + green + ',' + blue + '}\n'
313                           + '\\pagecolor{page_backgroundcolor}\n')
314
315
316 def revert_splitindex(document):
317     " Reverts splitindex-aware documents "
318     i = find_token(document.header, '\\use_indices', 0)
319     if i == -1:
320         document.warning("Malformed LyX document: Missing \\use_indices.")
321         return
322     indices = get_value(document.header, "\\use_indices", i)
323     preamble = ""
324     useindices = (indices == "true")
325     if useindices:
326          preamble += "\\usepackage{splitidx}\n"
327     del document.header[i]
328     
329     # deal with index declarations in the preamble
330     i = 0
331     while True:
332         i = find_token(document.header, "\\index", i)
333         if i == -1:
334             break
335         k = find_token(document.header, "\\end_index", i)
336         if k == -1:
337             document.warning("Malformed LyX document: Missing \\end_index.")
338             return
339         if useindices:    
340           line = document.header[i]
341           l = re.compile(r'\\index (.*)$')
342           m = l.match(line)
343           iname = m.group(1)
344           ishortcut = get_value(document.header, '\\shortcut', i, k)
345           if ishortcut != "":
346               preamble += "\\newindex[" + iname + "]{" + ishortcut + "}\n"
347         del document.header[i:k + 1]
348     if preamble != "":
349         insert_to_preamble(0, document, preamble)
350         
351     # deal with index insets
352     # these need to have the argument removed
353     i = 0
354     while True:
355         i = find_token(document.body, "\\begin_inset Index", i)
356         if i == -1:
357             break
358         line = document.body[i]
359         l = re.compile(r'\\begin_inset Index (.*)$')
360         m = l.match(line)
361         itype = m.group(1)
362         if itype == "idx" or indices == "false":
363             document.body[i] = "\\begin_inset Index"
364         else:
365             k = find_end_of_inset(document.body, i)
366             if k == -1:
367                 document.warning("Can't find end of index inset!")
368                 i += 1
369                 continue
370             content = lyx2latex(document, document.body[i:k])
371             # escape quotes
372             content = content.replace('"', r'\"')
373             subst = put_cmd_in_ert("\\sindex[" + itype + "]{" + content + "}")
374             document.body[i:k + 1] = subst
375         i = i + 1
376         
377     # deal with index_print insets
378     i = 0
379     while True:
380         i = find_token(document.body, "\\begin_inset CommandInset index_print", i)
381         if i == -1:
382             return
383         k = find_end_of_inset(document.body, i)
384         ptype = get_value(document.body, 'type', i, k).strip('"')
385         if ptype == "idx":
386             j = find_token(document.body, "type", i, k)
387             del document.body[j]
388         elif not useindices:
389             del document.body[i:k + 1]
390         else:
391             subst = put_cmd_in_ert("\\printindex[" + ptype + "]{}")
392             document.body[i:k + 1] = subst
393         i = i + 1
394
395
396 def convert_splitindex(document):
397     " Converts index and printindex insets to splitindex-aware format "
398     i = 0
399     while True:
400         i = find_token(document.body, "\\begin_inset Index", i)
401         if i == -1:
402             break
403         document.body[i] = document.body[i].replace("\\begin_inset Index",
404             "\\begin_inset Index idx")
405         i = i + 1
406     i = 0
407     while True:
408         i = find_token(document.body, "\\begin_inset CommandInset index_print", i)
409         if i == -1:
410             return
411         if document.body[i + 1].find('LatexCommand printindex') == -1:
412             document.warning("Malformed LyX document: Incomplete printindex inset.")
413             return
414         subst = ["LatexCommand printindex", 
415             "type \"idx\""]
416         document.body[i + 1:i + 2] = subst
417         i = i + 1
418
419
420 def revert_subindex(document):
421     " Reverts \\printsubindex CommandInset types "
422     i = find_token(document.header, '\\use_indices', 0)
423     if i == -1:
424         document.warning("Malformed LyX document: Missing \\use_indices.")
425         return
426     indices = get_value(document.header, "\\use_indices", i)
427     useindices = (indices == "true")
428     i = 0
429     while True:
430         i = find_token(document.body, "\\begin_inset CommandInset index_print", i)
431         if i == -1:
432             return
433         k = find_end_of_inset(document.body, i)
434         ctype = get_value(document.body, 'LatexCommand', i, k)
435         if ctype != "printsubindex":
436             i = k + 1
437             continue
438         ptype = get_value(document.body, 'type', i, k).strip('"')
439         if not useindices:
440             del document.body[i:k + 1]
441         else:
442             subst = put_cmd_in_ert("\\printsubindex[" + ptype + "]{}")
443             document.body[i:k + 1] = subst
444         i = i + 1
445
446
447 def revert_printindexall(document):
448     " Reverts \\print[sub]index* CommandInset types "
449     i = find_token(document.header, '\\use_indices', 0)
450     if i == -1:
451         document.warning("Malformed LyX document: Missing \\use_indices.")
452         return
453     indices = get_value(document.header, "\\use_indices", i)
454     useindices = (indices == "true")
455     i = 0
456     while True:
457         i = find_token(document.body, "\\begin_inset CommandInset index_print", i)
458         if i == -1:
459             return
460         k = find_end_of_inset(document.body, i)
461         ctype = get_value(document.body, 'LatexCommand', i, k)
462         if ctype != "printindex*" and ctype != "printsubindex*":
463             i = k
464             continue
465         if not useindices:
466             del document.body[i:k + 1]
467         else:
468             subst = put_cmd_in_ert("\\" + ctype + "{}")
469             document.body[i:k + 1] = subst
470         i = i + 1
471
472
473 def revert_strikeout(document):
474   " Reverts \\strikeout font attribute "
475   changed = revert_font_attrs(document, "\\uuline", "\\uuline")
476   changed = revert_font_attrs(document, "\\uwave", "\\uwave") or changed
477   changed = revert_font_attrs(document, "\\strikeout", "\\sout")  or changed
478   if changed == True:
479     insert_to_preamble(0, document,
480         '% Commands inserted by lyx2lyx for proper underlining\n'
481         + '\\PassOptionsToPackage{normalem}{ulem}\n'
482         + '\\usepackage{ulem}\n')
483
484
485 def revert_ulinelatex(document):
486     " Reverts \\uline font attribute "
487     i = find_token(document.body, '\\bar under', 0)
488     if i == -1:
489         return
490     insert_to_preamble(0, document,
491             '% Commands inserted by lyx2lyx for proper underlining\n'
492             + '\\PassOptionsToPackage{normalem}{ulem}\n'
493             + '\\usepackage{ulem}\n'
494             + '\\let\\cite@rig\\cite\n'
495             + '\\newcommand{\\b@xcite}[2][\\%]{\\def\\def@pt{\\%}\\def\\pas@pt{#1}\n'
496             + '  \\mbox{\\ifx\\def@pt\\pas@pt\\cite@rig{#2}\\else\\cite@rig[#1]{#2}\\fi}}\n'
497             + '\\renewcommand{\\underbar}[1]{{\\let\\cite\\b@xcite\\uline{#1}}}\n')
498
499
500 def revert_custom_processors(document):
501     " Remove bibtex_command and index_command params "
502     i = find_token(document.header, '\\bibtex_command', 0)
503     if i == -1:
504         document.warning("Malformed LyX document: Missing \\bibtex_command.")
505     else:
506         del document.header[i]
507     i = find_token(document.header, '\\index_command', 0)
508     if i == -1:
509         document.warning("Malformed LyX document: Missing \\index_command.")
510     else:
511         del document.header[i]
512
513
514 def convert_nomencl_width(document):
515     " Add set_width param to nomencl_print "
516     i = 0
517     while True:
518       i = find_token(document.body, "\\begin_inset CommandInset nomencl_print", i)
519       if i == -1:
520         break
521       document.body.insert(i + 2, "set_width \"none\"")
522       i = i + 1
523
524
525 def revert_nomencl_width(document):
526     " Remove set_width param from nomencl_print "
527     i = 0
528     while True:
529       i = find_token(document.body, "\\begin_inset CommandInset nomencl_print", i)
530       if i == -1:
531         break
532       j = find_end_of_inset(document.body, i)
533       l = find_token(document.body, "set_width", i, j)
534       if l == -1:
535             document.warning("Can't find set_width option for nomencl_print!")
536             i = j
537             continue
538       del document.body[l]
539       i = j - 1
540
541
542 def revert_nomencl_cwidth(document):
543     " Remove width param from nomencl_print "
544     i = 0
545     while True:
546       i = find_token(document.body, "\\begin_inset CommandInset nomencl_print", i)
547       if i == -1:
548         break
549       j = find_end_of_inset(document.body, i)
550       l = find_token(document.body, "width", i, j)
551       if l == -1:
552         document.warning("Can't find width option for nomencl_print!")
553         i = j
554         continue
555       width = get_value(document.body, "width", i, j).strip('"')
556       del document.body[l]
557       add_to_preamble(document, ["% this command was inserted by lyx2lyx"])
558       add_to_preamble(document, ["\\setlength{\\nomlabelwidth}{" + width + "}"])
559       i = j - 1
560
561
562 def revert_applemac(document):
563     " Revert applemac encoding to auto "
564     if document.encoding != "applemac":
565       return
566     document.encoding = "auto"
567     i = find_token(document.header, "\\encoding", 0)
568     if i != -1:
569         document.header[i] = "\\encoding auto"
570
571
572 def revert_longtable_align(document):
573     " Remove longtable alignment setting "
574     i = 0
575     while True:
576       i = find_token(document.body, "\\begin_inset Tabular", i)
577       if i == -1:
578           break
579       end = find_end_of_inset(document.body, i)
580       if end == -1:
581           document.warning("Can't find end of inset at line " + str(i))
582           i += 1
583           continue
584       fline = find_token(document.body, "<features", i, end)
585       if fline == -1:
586           document.warning("Can't find features for inset at line " + str(i))
587           i += 1
588           continue
589       j = document.body[fline].find("longtabularalignment")
590       if j == -1:
591           i += 1
592           continue
593       # FIXME Is this correct? It wipes out everything after the 
594       # one we found.
595       document.body[fline] = document.body[fline][:j - 1] + '>'
596       # since there could be a tabular inside this one, we 
597       # cannot jump to end.
598       i += 1
599
600
601 def revert_branch_filename(document):
602     " Remove \\filename_suffix parameter from branches "
603     i = 0
604     while True:
605         i = find_token(document.header, "\\filename_suffix", i)
606         if i == -1:
607             return
608         del document.header[i]
609
610
611 def revert_paragraph_indentation(document):
612     " Revert custom paragraph indentation to preamble code "
613     i = find_token(document.header, "\\paragraph_indentation", 0)
614     if i == -1:
615       return
616     length = get_value(document.header, "\\paragraph_indentation", i)
617     # we need only remove the line if indentation is default
618     if length != "default":
619       # handle percent lengths
620       length = latex_length(length)[1]
621       add_to_preamble(document, ["% this command was inserted by lyx2lyx"])
622       add_to_preamble(document, ["\\setlength{\\parindent}{" + length + "}"])
623     del document.header[i]
624
625
626 def revert_percent_skip_lengths(document):
627     " Revert relative lengths for paragraph skip separation to preamble code "
628     i = find_token(document.header, "\\defskip", 0)
629     if i == -1:
630         return
631     length = get_value(document.header, "\\defskip", i)
632     # only revert when a custom length was set and when
633     # it used a percent length
634     if length in ('smallskip', 'medskip', 'bigskip'):
635         return
636     # handle percent lengths
637     percent, length = latex_length(length)
638     if percent:
639         add_to_preamble(document, ["% this command was inserted by lyx2lyx"])
640         add_to_preamble(document, ["\\setlength{\\parskip}{" + length + "}"])
641         # set defskip to medskip as default
642         document.header[i] = "\\defskip medskip"
643
644
645 def revert_percent_vspace_lengths(document):
646     " Revert relative VSpace lengths to ERT "
647     i = 0
648     while True:
649       i = find_token(document.body, "\\begin_inset VSpace", i)
650       if i == -1:
651           break
652       # only revert if a custom length was set and if
653       # it used a percent length
654       r = re.compile(r'\\begin_inset VSpace (.*)$')
655       m = r.match(document.body[i])
656       length = m.group(1)
657       if length in ('defskip', 'smallskip', 'medskip', 'bigskip', 'vfill'):
658          i += 1
659          continue
660       # check if the space has a star (protected space)
661       protected = (document.body[i].rfind("*") != -1)
662       if protected:
663           length = length.rstrip('*')
664       # handle percent lengths
665       percent, length = latex_length(length)
666       # revert the VSpace inset to ERT
667       if percent:
668           if protected:
669               subst = put_cmd_in_ert("\\vspace*{" + length + "}")
670           else:
671               subst = put_cmd_in_ert("\\vspace{" + length + "}")
672           document.body[i:i + 2] = subst
673       i += 1
674
675
676 def revert_percent_hspace_lengths(document):
677     " Revert relative HSpace lengths to ERT "
678     i = 0
679     while True:
680       i = find_token(document.body, "\\begin_inset space \\hspace", i)
681       if i == -1:
682           break
683       j = find_end_of_inset(document.body, i)
684       if j == -1:
685           document.warning("Can't find end of inset at line " + str(i))
686           i += 1
687           continue
688       # only revert if a custom length was set...
689       length = get_value(document.body, '\\length', i + 1, j)
690       if length == '':
691           document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
692           i = j
693           continue
694       protected = ""
695       if document.body[i].find("\\hspace*{}") != -1:
696           protected = "*"
697       # ...and if it used a percent length
698       percent, length = latex_length(length)
699       # revert the HSpace inset to ERT
700       if percent:
701           subst = put_cmd_in_ert("\\hspace" + protected + "{" + length + "}")
702           document.body[i:j + 1] = subst
703       # if we did a substitution, this will still be ok
704       i = j
705
706
707 def revert_hspace_glue_lengths(document):
708     " Revert HSpace glue lengths to ERT "
709     i = 0
710     while True:
711       i = find_token(document.body, "\\begin_inset space \\hspace", i)
712       if i == -1:
713           break
714       j = find_end_of_inset(document.body, i)
715       if j == -1:
716           document.warning("Can't find end of inset at line " + str(i))
717           i += 1
718           continue
719       length = get_value(document.body, '\\length', i + 1, j)
720       if length == '':
721           document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
722           i = j
723           continue
724       protected = ""
725       if document.body[i].find("\\hspace*{}") != -1:
726           protected = "*"
727       # only revert if the length contains a plus or minus at pos != 0
728       if length.find('-',1) != -1 or length.find('+',1) != -1:
729           # handle percent lengths
730           length = latex_length(length)[1]
731           # revert the HSpace inset to ERT
732           subst = put_cmd_in_ert("\\hspace" + protected + "{" + length + "}")
733           document.body[i:j+1] = subst
734       i = j
735
736
737 def convert_author_id(document):
738     " Add the author_id to the \\author definition and make sure 0 is not used"
739     i = 0
740     anum = 1
741     re_author = re.compile(r'(\\author) (\".*\")\s*(.*)$')
742     
743     while True:
744         i = find_token(document.header, "\\author", i)
745         if i == -1:
746             break
747         m = re_author.match(document.header[i])
748         if m:
749             name = m.group(2)
750             email = m.group(3)
751             document.header[i] = "\\author %i %s %s" % (anum, name, email)
752         # FIXME Should this really be incremented if we didn't match?
753         anum += 1
754         i += 1
755         
756     i = 0
757     while True:
758         i = find_token(document.body, "\\change_", i)
759         if i == -1:
760             break
761         change = document.body[i].split(' ');
762         if len(change) == 3:
763             type = change[0]
764             author_id = int(change[1])
765             time = change[2]
766             document.body[i] = "%s %i %s" % (type, author_id + 1, time)
767         i += 1
768
769
770 def revert_author_id(document):
771     " Remove the author_id from the \\author definition "
772     i = 0
773     anum = 0
774     rx = re.compile(r'(\\author)\s+(\d+)\s+(\".*\")\s*(.*)$')
775     idmap = dict()
776
777     while True:
778         i = find_token(document.header, "\\author", i)
779         if i == -1:
780             break
781         m = rx.match(document.header[i])
782         if m:
783             author_id = int(m.group(2))
784             idmap[author_id] = anum
785             name = m.group(3)
786             email = m.group(4)
787             document.header[i] = "\\author %s %s" % (name, email)
788         i += 1
789         # FIXME Should this be incremented if we didn't match?
790         anum += 1
791
792     i = 0
793     while True:
794         i = find_token(document.body, "\\change_", i)
795         if i == -1:
796             break
797         change = document.body[i].split(' ');
798         if len(change) == 3:
799             type = change[0]
800             author_id = int(change[1])
801             time = change[2]
802             document.body[i] = "%s %i %s" % (type, idmap[author_id], time)
803         i += 1
804
805
806 def revert_suppress_date(document):
807     " Revert suppressing of default document date to preamble code "
808     i = find_token(document.header, "\\suppress_date", 0)
809     if i == -1:
810         return
811     # remove the preamble line and write to the preamble
812     # when suppress_date was true
813     date = get_value(document.header, "\\suppress_date", i)
814     if date == "true":
815         add_to_preamble(document, ["% this command was inserted by lyx2lyx"])
816         add_to_preamble(document, ["\\date{}"])
817     del document.header[i]
818
819
820 def revert_mhchem(document):
821     "Revert mhchem loading to preamble code"
822
823     mhchem = "off"
824     i = find_token(document.header, "\\use_mhchem", 0)
825     if i == -1:
826         document.warning("Malformed LyX document: Could not find mhchem setting.")
827         mhchem = "auto"
828     else:
829         val = get_value(document.header, "\\use_mhchem", i)
830         if val == "1":
831             mhchem = "auto"
832         elif val == "2":
833             mhchem = "on"
834         del document.header[i]
835
836     if mhchem == "auto":
837         i = 0
838         while True:
839             i = find_token(document.body, "\\begin_inset Formula", i)
840             if i == -1:
841                break
842             line = document.body[i]
843             if line.find("\\ce{") != -1 or line.find("\\cf{") != 1:
844               mhchem = "on"
845               break
846             i += 1
847
848     if mhchem == "on":
849         pre = ["% lyx2lyx mhchem commands", 
850           "\\PassOptionsToPackage{version=3}{mhchem}", 
851           "\\usepackage{mhchem}"]
852         add_to_preamble(document, pre) 
853
854
855 def revert_fontenc(document):
856     " Remove fontencoding param "
857     i = find_token(document.header, '\\fontencoding', 0)
858     if i == -1:
859         document.warning("Malformed LyX document: Missing \\fontencoding.")
860         return
861     del document.header[i]
862
863
864 def merge_gbrief(document):
865     " Merge g-brief-en and g-brief-de to one class "
866
867     if document.textclass != "g-brief-de":
868         if document.textclass == "g-brief-en":
869             document.textclass = "g-brief"
870             document.set_textclass()
871         return
872
873     obsoletedby = { "Brieftext":       "Letter",
874                     "Unterschrift":    "Signature",
875                     "Strasse":         "Street",
876                     "Zusatz":          "Addition",
877                     "Ort":             "Town",
878                     "Land":            "State",
879                     "RetourAdresse":   "ReturnAddress",
880                     "MeinZeichen":     "MyRef",
881                     "IhrZeichen":      "YourRef",
882                     "IhrSchreiben":    "YourMail",
883                     "Telefon":         "Phone",
884                     "BLZ":             "BankCode",
885                     "Konto":           "BankAccount",
886                     "Postvermerk":     "PostalComment",
887                     "Adresse":         "Address",
888                     "Datum":           "Date",
889                     "Betreff":         "Reference",
890                     "Anrede":          "Opening",
891                     "Anlagen":         "Encl.",
892                     "Verteiler":       "cc",
893                     "Gruss":           "Closing"}
894     i = 0
895     while 1:
896         i = find_token(document.body, "\\begin_layout", i)
897         if i == -1:
898             break
899
900         layout = document.body[i][14:]
901         if layout in obsoletedby:
902             document.body[i] = "\\begin_layout " + obsoletedby[layout]
903
904         i += 1
905         
906     document.textclass = "g-brief"
907     document.set_textclass()
908
909
910 def revert_gbrief(document):
911     " Revert g-brief to g-brief-en "
912     if document.textclass == "g-brief":
913         document.textclass = "g-brief-en"
914         document.set_textclass()
915
916
917 def revert_html_options(document):
918     " Remove html options "
919     i = find_token(document.header, '\\html_use_mathml', 0)
920     if i != -1:
921         del document.header[i]
922     i = find_token(document.header, '\\html_be_strict', 0)
923     if i != -1:
924         del document.header[i]
925
926
927 def revert_includeonly(document):
928     i = 0
929     while True:
930         i = find_token(document.header, "\\begin_includeonly", i)
931         if i == -1:
932             return
933         j = find_end_of(document.header, i, "\\begin_includeonly", "\\end_includeonly")
934         if j == -1:
935             document.warning("Unable to find end of includeonly section!!")
936             break
937         document.header[i : j + 1] = []
938
939
940 def revert_includeall(document):
941     " Remove maintain_unincluded_children param "
942     i = find_token(document.header, '\\maintain_unincluded_children', 0)
943     if i != -1:
944         del document.header[i]
945
946
947 def revert_multirow(document):
948     " Revert multirow cells in tables to TeX-code"
949     i = 0
950     multirow = False
951     while True:
952       # cell type 3 is multirow begin cell
953       i = find_token(document.body, '<cell multirow="3"', i)
954       if i == -1:
955           break
956       # a multirow cell was found
957       multirow = True
958       # remove the multirow tag, set the valignment to top
959       # and remove the bottom line
960       # FIXME Are we sure these always have space around them?
961       document.body[i] = document.body[i].replace(' multirow="3" ', ' ')
962       document.body[i] = document.body[i].replace('valignment="middle"', 'valignment="top"')
963       document.body[i] = document.body[i].replace(' bottomline="true" ', ' ')
964       # write ERT to create the multirow cell
965       # use 2 rows and 2cm as default with because the multirow span
966       # and the column width is only hardly accessible
967       cend = find_token(document.body, "</cell>", i)
968       if cend == -1:
969           document.warning("Malformed LyX document: Could not find end of tabular cell.")
970           i += 1
971           continue
972       blay = find_token(document.body, "\\begin_layout", i, cend)
973       if blay == -1:
974           document.warning("Can't find layout for cell!")
975           i = j
976           continue
977       bend = find_end_of_layout(document.body, blay)
978       if blay == -1:
979           document.warning("Can't find end of layout for cell!")
980           i = cend
981           continue
982
983       # do the later one first, so as not to mess up the numbering
984       # we are wrapping the whole cell in this ert
985       # so before the end of the layout...
986       document.body[bend:bend] = put_cmd_in_ert("}")
987       # ...and after the beginning
988       document.body[blay+1:blay+1] = put_cmd_in_ert("\\multirow{2}{2cm}{")
989
990       while True:
991           # cell type 4 is multirow part cell
992           k = find_token(document.body, '<cell multirow="4"', cend)
993           if k == -1:
994               break
995           # remove the multirow tag, set the valignment to top
996           # and remove the top line
997           # FIXME Are we sure these always have space around them?
998           document.body[k] = document.body[k].replace(' multirow="4" ', ' ')
999           document.body[k] = document.body[k].replace('valignment="middle"', 'valignment="top"')
1000           document.body[k] = document.body[k].replace(' topline="true" ', ' ')
1001           k += 1
1002       # this will always be ok
1003       i = cend
1004
1005     if multirow == True:
1006         add_to_preamble(document, 
1007           ["% lyx2lyx multirow additions ", "\\usepackage{multirow}"])
1008
1009
1010 def convert_math_output(document):
1011     " Convert \html_use_mathml to \html_math_output "
1012     i = find_token(document.header, "\\html_use_mathml", 0)
1013     if i == -1:
1014         return
1015     rgx = re.compile(r'\\html_use_mathml\s+(\w+)')
1016     m = rgx.match(document.header[i])
1017     newval = "0" # MathML
1018     if m:
1019       val = m.group(1)
1020       if val != "true":
1021         newval = "2" # Images
1022     else:
1023       document.warning("Can't match " + document.header[i])
1024     document.header[i] = "\\html_math_output " + newval
1025
1026
1027 def revert_math_output(document):
1028     " Revert \html_math_output to \html_use_mathml "
1029     i = find_token(document.header, "\\html_math_output", 0)
1030     if i == -1:
1031         return
1032     rgx = re.compile(r'\\html_math_output\s+(\d)')
1033     m = rgx.match(document.header[i])
1034     newval = "true"
1035     if m:
1036         val = m.group(1)
1037         if val == "1" or val == "2":
1038             newval = "false"
1039     else:
1040         document.warning("Unable to match " + document.header[i])
1041     document.header[i] = "\\html_use_mathml " + newval
1042                 
1043
1044
1045 def revert_inset_preview(document):
1046     " Dissolves the preview inset "
1047     i = 0
1048     while True:
1049       i = find_token(document.body, "\\begin_inset Preview", i)
1050       if i == -1:
1051           return
1052       iend = find_end_of_inset(document.body, i)
1053       if iend == -1:
1054           document.warning("Malformed LyX document: Could not find end of Preview inset.")
1055           i += 1
1056           continue
1057       
1058       # This has several issues.
1059       # We need to do something about the layouts inside InsetPreview.
1060       # If we just leave the first one, then we have something like:
1061       # \begin_layout Standard
1062       # ...
1063       # \begin_layout Standard
1064       # and we get a "no \end_layout" error. So something has to be done.
1065       # Ideally, we would check if it is the same as the layout we are in.
1066       # If so, we just remove it; if not, we end the active one. But it is 
1067       # not easy to know what layout we are in, due to depth changes, etc,
1068       # and it is not clear to me how much work it is worth doing. In most
1069       # cases, the layout will probably be the same.
1070       # 
1071       # For the same reason, we have to remove the \end_layout tag at the
1072       # end of the last layout in the inset. Again, that will sometimes be
1073       # wrong, but it will usually be right. To know what to do, we would
1074       # again have to know what layout the inset is in.
1075       
1076       blay = find_token(document.body, "\\begin_layout", i, iend)
1077       if blay == -1:
1078           document.warning("Can't find layout for preview inset!")
1079           # always do the later one first...
1080           del document.body[iend]
1081           del document.body[i]
1082           # deletions mean we do not need to reset i
1083           continue
1084
1085       # This is where we would check what layout we are in.
1086       # The check for Standard is definitely wrong.
1087       # 
1088       # lay = document.body[blay].split(None, 1)[1]
1089       # if lay != oldlayout:
1090       #     # record a boolean to tell us what to do later....
1091       #     # better to do it later, since (a) it won't mess up
1092       #     # the numbering and (b) we only modify at the end.
1093         
1094       # we want to delete the last \\end_layout in this inset, too.
1095       # note that this may not be the \\end_layout that goes with blay!!
1096       bend = find_end_of_layout(document.body, blay)
1097       while True:
1098           tmp = find_token(document.body, "\\end_layout", bend + 1, iend)
1099           if tmp == -1:
1100               break
1101           bend = tmp
1102       if bend == blay:
1103           document.warning("Unable to find last layout in preview inset!")
1104           del document.body[iend]
1105           del document.body[i]
1106           # deletions mean we do not need to reset i
1107           continue
1108       # always do the later one first...
1109       del document.body[iend]
1110       del document.body[bend]
1111       del document.body[i:blay + 1]
1112       # we do not need to reset i
1113                 
1114
1115 def revert_equalspacing_xymatrix(document):
1116     " Revert a Formula with xymatrix@! to an ERT inset "
1117     i = 0
1118     has_preamble = False
1119     has_equal_spacing = False
1120
1121     while True:
1122       i = find_token(document.body, "\\begin_inset Formula", i)
1123       if i == -1:
1124           break
1125       j = find_end_of_inset(document.body, i)
1126       if j == -1:
1127           document.warning("Malformed LyX document: Could not find end of Formula inset.")
1128           i += 1
1129           continue
1130       
1131       for curline in range(i,j):
1132           found = document.body[curline].find("\\xymatrix@!")
1133           if found != -1:
1134               break
1135  
1136       if found != -1:
1137           has_equal_spacing = True
1138           content = [document.body[i][21:]]
1139           content += document.body[i + 1:j]
1140           subst = put_cmd_in_ert(content)
1141           document.body[i:j + 1] = subst
1142           i += len(subst) - (j - i) + 1
1143       else:
1144           for curline in range(i,j):
1145               l = document.body[curline].find("\\xymatrix")
1146               if l != -1:
1147                   has_preamble = True;
1148                   break;
1149           i = j + 1
1150   
1151     if has_equal_spacing and not has_preamble:
1152         add_to_preamble(document, ['% lyx2lyx xymatrix addition', '\\usepackage[all]{xy}'])
1153
1154
1155 def revert_notefontcolor(document):
1156     " Reverts greyed-out note font color to preamble code "
1157
1158     i = find_token(document.header, "\\notefontcolor", 0)
1159     if i == -1:
1160         return
1161
1162     # are there any grey notes?
1163     if find_token(document.body, "\\begin_inset Note Greyedout", 0) == -1:
1164         # no need to do anything, and \renewcommand will throw an error
1165         # since lyxgreyedout will not exist.
1166         return
1167
1168     colorcode = get_value(document.header, '\\notefontcolor', i)
1169     del document.header[i]
1170     # the color code is in the form #rrggbb where every character denotes a hex number
1171     red = hex2ratio(colorcode[1:3])
1172     green = hex2ratio(colorcode[3:5])
1173     blue = hex2ratio(colorcode[5:7])
1174     # write the preamble
1175     insert_to_preamble(0, document,
1176       ['% Commands inserted by lyx2lyx to set the font color',
1177         '% for greyed-out notes',
1178         '\\@ifundefined{definecolor}{\\usepackage{color}}{}'
1179         '\\definecolor{note_fontcolor}{rgb}{%s,%s,%s}' % (red, green, blue),
1180         '\\renewenvironment{lyxgreyedout}',
1181         ' {\\textcolor{note_fontcolor}\\bgroup}{\\egroup}'])
1182
1183
1184 def revert_turkmen(document):
1185     "Set language Turkmen to English" 
1186
1187     if document.language == "turkmen": 
1188         document.language = "english" 
1189         i = find_token(document.header, "\\language", 0) 
1190         if i != -1: 
1191             document.header[i] = "\\language english" 
1192
1193     j = 0 
1194     while True: 
1195         j = find_token(document.body, "\\lang turkmen", j) 
1196         if j == -1: 
1197             return 
1198         document.body[j] = document.body[j].replace("\\lang turkmen", "\\lang english") 
1199         j += 1 
1200
1201
1202 def revert_fontcolor(document):
1203     " Reverts font color to preamble code "
1204     i = find_token(document.header, "\\fontcolor", 0)
1205     if i == -1:
1206         return
1207     colorcode = get_value(document.header, '\\fontcolor', i)
1208     del document.header[i]
1209     # don't clutter the preamble if font color is not set
1210     if colorcode == "#000000":
1211         return
1212     # the color code is in the form #rrggbb where every character denotes a hex number
1213     red = hex2ratio(colorcode[1:3])
1214     green = hex2ratio(colorcode[3:5])
1215     blue = hex2ratio(colorcode[5:7])
1216     # write the preamble
1217     insert_to_preamble(0, document,
1218       ['% Commands inserted by lyx2lyx to set the font color',
1219       '\\@ifundefined{definecolor}{\\usepackage{color}}{}',
1220       '\\definecolor{document_fontcolor}{rgb}{%s,%s,%s}' % (red, green, blue),
1221       '\\color{document_fontcolor}'])
1222
1223
1224 def revert_shadedboxcolor(document):
1225     " Reverts shaded box color to preamble code "
1226     i = find_token(document.header, "\\boxbgcolor", 0)
1227     if i == -1:
1228         return
1229     colorcode = get_value(document.header, '\\boxbgcolor', i)
1230     del document.header[i]
1231     # the color code is in the form #rrggbb
1232     red = hex2ratio(colorcode[1:3])
1233     green = hex2ratio(colorcode[3:5])
1234     blue = hex2ratio(colorcode[5:7])
1235     # write the preamble
1236     insert_to_preamble(0, document,
1237       ['% Commands inserted by lyx2lyx to set the color of boxes with shaded background',
1238       '\\@ifundefined{definecolor}{\\usepackage{color}}{}',
1239       "\\definecolor{shadecolor}{rgb}{%s,%s,%s}" % (red, green, blue)])
1240
1241
1242 def revert_lyx_version(document):
1243     " Reverts LyX Version information from Inset Info "
1244     version = "LyX version"
1245     try:
1246         import lyx2lyx_version
1247         version = lyx2lyx_version.version
1248     except:
1249         pass
1250
1251     i = 0
1252     while 1:
1253         i = find_token(document.body, '\\begin_inset Info', i)
1254         if i == -1:
1255             return
1256         j = find_end_of_inset(document.body, i + 1)
1257         if j == -1:
1258             document.warning("Malformed LyX document: Could not find end of Info inset.")
1259             i += 1
1260             continue
1261
1262         # We expect:
1263         # \begin_inset Info
1264         # type  "lyxinfo"
1265         # arg   "version"
1266         # \end_inset
1267         # but we shall try to be forgiving.
1268         arg = typ = ""
1269         for k in range(i, j):
1270             if document.body[k].startswith("arg"):
1271                 arg = document.body[k][3:].strip().strip('"')
1272             if document.body[k].startswith("type"):
1273                 typ = document.body[k][4:].strip().strip('"')
1274         if arg != "version" or typ != "lyxinfo":
1275             i = j + 1
1276             continue
1277
1278         # We do not actually know the version of LyX used to produce the document.
1279         # But we can use our version, since we are reverting.
1280         s = [version]
1281         # Now we want to check if the line after "\end_inset" is empty. It normally
1282         # is, so we want to remove it, too.
1283         lastline = j + 1
1284         if document.body[j + 1].strip() == "":
1285             lastline = j + 2
1286         document.body[i: lastline] = s
1287         i = i + 1
1288
1289
1290 def revert_math_scale(document):
1291   " Remove math scaling and LaTeX options "
1292   i = find_token(document.header, '\\html_math_img_scale', 0)
1293   if i != -1:
1294     del document.header[i]
1295   i = find_token(document.header, '\\html_latex_start', 0)
1296   if i != -1:
1297     del document.header[i]
1298   i = find_token(document.header, '\\html_latex_end', 0)
1299   if i != -1:
1300     del document.header[i]
1301
1302
1303 def revert_pagesizes(document):
1304   " Revert page sizes to default "
1305   i = find_token(document.header, '\\papersize', 0)
1306   if i != -1:
1307     size = document.header[i][11:]
1308     if size == "a0paper" or size == "a1paper" or size == "a2paper" \
1309     or size == "a6paper" or size == "b0paper" or size == "b1paper" \
1310     or size == "b2paper" or size == "b6paper" or size == "b0j" \
1311     or size == "b1j" or size == "b2j" or size == "b3j" or size == "b4j" \
1312     or size == "b5j" or size == "b6j":
1313       del document.header[i]
1314
1315
1316 def revert_DIN_C_pagesizes(document):
1317   " Revert DIN C page sizes to default "
1318   i = find_token(document.header, '\\papersize', 0)
1319   if i != -1:
1320     size = document.header[i][11:]
1321     if size == "c0paper" or size == "c1paper" or size == "c2paper" \
1322     or size == "c3paper" or size == "c4paper" or size == "c5paper" \
1323     or size == "c6paper":
1324       del document.header[i]
1325
1326
1327 def convert_html_quotes(document):
1328   " Remove quotes around html_latex_start and html_latex_end "
1329
1330   i = find_token(document.header, '\\html_latex_start', 0)
1331   if i != -1:
1332     line = document.header[i]
1333     l = re.compile(r'\\html_latex_start\s+"(.*)"')
1334     m = l.match(line)
1335     if m:
1336       document.header[i] = "\\html_latex_start " + m.group(1)
1337       
1338   i = find_token(document.header, '\\html_latex_end', 0)
1339   if i != -1:
1340     line = document.header[i]
1341     l = re.compile(r'\\html_latex_end\s+"(.*)"')
1342     m = l.match(line)
1343     if m:
1344       document.header[i] = "\\html_latex_end " + m.group(1)
1345       
1346
1347 def revert_html_quotes(document):
1348   " Remove quotes around html_latex_start and html_latex_end "
1349   
1350   i = find_token(document.header, '\\html_latex_start', 0)
1351   if i != -1:
1352     line = document.header[i]
1353     l = re.compile(r'\\html_latex_start\s+(.*)')
1354     m = l.match(line)
1355     if not m:
1356         document.warning("Weird html_latex_start line: " + line)
1357         del document.header[i]
1358     else:
1359         document.header[i] = "\\html_latex_start \"" + m.group(1) + "\""
1360       
1361   i = find_token(document.header, '\\html_latex_end', 0)
1362   if i != -1:
1363     line = document.header[i]
1364     l = re.compile(r'\\html_latex_end\s+(.*)')
1365     m = l.match(line)
1366     if not m:
1367         document.warning("Weird html_latex_end line: " + line)
1368         del document.header[i]
1369     else:
1370         document.header[i] = "\\html_latex_end \"" + m.group(1) + "\""
1371
1372
1373 def revert_output_sync(document):
1374   " Remove forward search options "
1375   i = find_token(document.header, '\\output_sync_macro', 0)
1376   if i != -1:
1377     del document.header[i]
1378   i = find_token(document.header, '\\output_sync', 0)
1379   if i != -1:
1380     del document.header[i]
1381
1382
1383 # FIXME This doesn't do anything!!
1384 def revert_align_decimal(document):
1385   l = 0
1386   while True:
1387     l = document.body[l].find('alignment=decimal')
1388     if l == -1:
1389         break
1390     remove_option(document, l, 'decimal_point')
1391     document.body[l].replace('decimal', 'center')
1392
1393
1394 def convert_optarg(document):
1395   " Convert \\begin_inset OptArg to \\begin_inset Argument "
1396   i = 0
1397   while 1:
1398     i = find_token(document.body, '\\begin_inset OptArg', i)
1399     if i == -1:
1400       return
1401     document.body[i] = "\\begin_inset Argument"
1402     i += 1
1403
1404
1405 def revert_argument(document):
1406   " Convert \\begin_inset Argument to \\begin_inset OptArg "
1407   i = 0
1408   while 1:
1409     i = find_token(document.body, '\\begin_inset Argument', i)
1410     if i == -1:
1411       return
1412     document.body[i] = "\\begin_inset OptArg"
1413     i += 1
1414
1415
1416 def revert_makebox(document):
1417   " Convert \\makebox to TeX code "
1418   i = 0
1419   while 1:
1420     # only revert frameless boxes without an inner box
1421     i = find_token(document.body, '\\begin_inset Box Frameless', i)
1422     if i == -1:
1423       return
1424     z = find_end_of_inset(document.body, i)
1425     if z == -1:
1426       document.warning("Malformed LyX document: Can't find end of box inset.")
1427       i += 1
1428       continue
1429     blay = find_token(document.body, "\\begin_layout", i, z)
1430     if blay == -1:
1431       document.warning("Malformed LyX document: Can't find layout in box.")
1432       i = z
1433       continue
1434     # by looking before the layout we make sure we're actually finding
1435     # an option, not text.
1436     j = find_token(document.body, 'use_makebox', i, blay)
1437     if j == -1:
1438         i = z
1439         continue
1440     val = get_value(document.body, 'use_makebox', j)
1441     if val != "1":
1442         del document.body[j]
1443         i = z
1444         continue
1445     bend = find_end_of_layout(document.body, blay)
1446     if bend == -1 or bend > z:
1447         document.warning("Malformed LyX document: Can't find end of layout in box.")
1448         i = z
1449         continue
1450     # determine the alignment
1451     align = get_value(document.body, 'hor_pos', i, blay, "c").strip('"')
1452     # determine the width
1453     length = get_value(document.body, 'width', i, blay, "50col%").strip('"')
1454     length = latex_length(length)[1]
1455     # remove the \end_layout \end_inset pair
1456     document.body[bend:z + 1] = put_cmd_in_ert("}")
1457     subst = "\\makebox[" + length + "][" \
1458       + align + "]{"
1459     document.body[i:blay + 1] = put_cmd_in_ert(subst)
1460     i += 1
1461
1462
1463 def convert_use_makebox(document):
1464   " Adds use_makebox option for boxes "
1465   i = 0
1466   while 1:
1467     i = find_token(document.body, '\\begin_inset Box', i)
1468     if i == -1:
1469       return
1470     # all of this is to make sure we actually find the use_parbox
1471     # that is an option for this box, not some text elsewhere.
1472     z = find_end_of_inset(document.body, i)
1473     if z == -1:
1474       document.warning("Can't find end of box inset!!")
1475       i += 1
1476       continue
1477     blay = find_token(document.body, "\\begin_layout", i, z)
1478     if blay == -1:
1479       document.warning("Can't find layout in box inset!!")
1480       i = z
1481       continue
1482     # so now we are looking for use_parbox before the box's layout
1483     k = find_token(document.body, 'use_parbox', i, blay)
1484     if k == -1:
1485       document.warning("Malformed LyX document: Can't find use_parbox statement in box.")
1486       i = z
1487       continue
1488     document.body.insert(k + 1, "use_makebox 0")
1489     i = z + 1
1490
1491
1492 def revert_IEEEtran(document):
1493   " Convert IEEEtran layouts and styles to TeX code "
1494   if document.textclass != "IEEEtran":
1495     return
1496   revert_flex_inset(document, "IEEE membership", "\\IEEEmembership", 0)
1497   revert_flex_inset(document, "Lowercase", "\\MakeLowercase", 0)
1498   layouts = ("Special Paper Notice", "After Title Text", "Publication ID",
1499              "Page headings", "Biography without photo")
1500   latexcmd = {"Special Paper Notice": "\\IEEEspecialpapernotice",
1501               "After Title Text":     "\\IEEEaftertitletext",
1502               "Publication ID":       "\\IEEEpubid"}
1503   obsoletedby = {"Page headings":            "MarkBoth",
1504                  "Biography without photo":  "BiographyNoPhoto"}
1505   for layout in layouts:
1506     i = 0
1507     while True:
1508         i = find_token(document.body, '\\begin_layout ' + layout, i)
1509         if i == -1:
1510           break
1511         j = find_end_of_layout(document.body, i)
1512         if j == -1:
1513           document.warning("Malformed LyX document: Can't find end of " + layout + " layout.")
1514           i += 1
1515           continue
1516         if layout in obsoletedby:
1517           document.body[i] = "\\begin_layout " + obsoletedby[layout]
1518           i = j
1519           continue
1520         content = lyx2latex(document, document.body[i:j + 1])
1521         add_to_preamble(document, [latexcmd[layout] + "{" + content + "}"])
1522         del document.body[i:j + 1]
1523         # no need to reset i
1524
1525
1526 def convert_prettyref(document):
1527         " Converts prettyref references to neutral formatted refs "
1528         re_ref = re.compile("^\s*reference\s+\"(\w+):(\S+)\"")
1529         nm_ref = re.compile("^\s*name\s+\"(\w+):(\S+)\"")
1530
1531         i = 0
1532         while True:
1533                 i = find_token(document.body, "\\begin_inset CommandInset ref", i)
1534                 if i == -1:
1535                         break
1536                 j = find_end_of_inset(document.body, i)
1537                 if j == -1:
1538                         document.warning("Malformed LyX document: No end of InsetRef!")
1539                         i += 1
1540                         continue
1541                 k = find_token(document.body, "LatexCommand prettyref", i, j)
1542                 if k != -1:
1543                         document.body[k] = "LatexCommand formatted"
1544                 i = j + 1
1545         document.header.insert(-1, "\\use_refstyle 0")
1546                 
1547  
1548 def revert_refstyle(document):
1549         " Reverts neutral formatted refs to prettyref "
1550         re_ref = re.compile("^reference\s+\"(\w+):(\S+)\"")
1551         nm_ref = re.compile("^\s*name\s+\"(\w+):(\S+)\"")
1552
1553         i = 0
1554         while True:
1555                 i = find_token(document.body, "\\begin_inset CommandInset ref", i)
1556                 if i == -1:
1557                         break
1558                 j = find_end_of_inset(document.body, i)
1559                 if j == -1:
1560                         document.warning("Malformed LyX document: No end of InsetRef")
1561                         i += 1
1562                         continue
1563                 k = find_token(document.body, "LatexCommand formatted", i, j)
1564                 if k != -1:
1565                         document.body[k] = "LatexCommand prettyref"
1566                 i = j + 1
1567         i = find_token(document.header, "\\use_refstyle", 0)
1568         if i != -1:
1569                 document.header.pop(i)
1570  
1571
1572 def revert_nameref(document):
1573   " Convert namerefs to regular references "
1574   cmds = ["Nameref", "nameref"]
1575   foundone = False
1576   rx = re.compile(r'reference "(.*)"')
1577   for cmd in cmds:
1578     i = 0
1579     oldcmd = "LatexCommand " + cmd
1580     while 1:
1581       # It seems better to look for this, as most of the reference
1582       # insets won't be ones we care about.
1583       i = find_token(document.body, oldcmd, i)
1584       if i == -1:
1585         break
1586       cmdloc = i
1587       i += 1
1588       # Make sure it is actually in an inset!
1589       # A normal line could begin with "LatexCommand nameref"!
1590       stins, endins = get_containing_inset(document.body, cmdloc, \
1591           "\\begin_inset CommandInset ref")
1592       if stins == -1:
1593         continue
1594
1595       # ok, so it is in an InsetRef
1596       refline = find_token(document.body, "reference", stins, endins)
1597       if refline == -1:
1598         document.warning("Can't find reference for inset at line " + stinst + "!!")
1599         continue
1600       m = rx.match(document.body[refline])
1601       if not m:
1602         document.warning("Can't match reference line: " + document.body[ref])
1603         continue
1604       foundone = True
1605       ref = m.group(1)
1606       newcontent = put_cmd_in_ert('\\' + cmd + '{' + ref + '}')
1607       document.body[stins:endins + 1] = newcontent
1608
1609   if foundone:
1610     add_to_preamble(document, "\usepackage{nameref}")
1611
1612
1613 def remove_Nameref(document):
1614   " Convert Nameref commands to nameref commands "
1615   i = 0
1616   while 1:
1617     # It seems better to look for this, as most of the reference
1618     # insets won't be ones we care about.
1619     i = find_token(document.body, "LatexCommand Nameref" , i)
1620     if i == -1:
1621       break
1622     cmdloc = i
1623     i += 1
1624     
1625     # Make sure it is actually in an inset!
1626     stins, endins = get_containing_inset(document.body, \
1627         cmdloc, "\\begin_inset CommandInset ref")
1628     if stins == -1:
1629       continue
1630     document.body[cmdloc] = "LatexCommand nameref"
1631
1632
1633 def revert_mathrsfs(document):
1634     " Load mathrsfs if \mathrsfs us use in the document "
1635     i = 0
1636     end = len(document.body) - 1
1637     while True:
1638       j = document.body[i].find("\\mathscr{")
1639       if j != -1:
1640         add_to_preamble(document, ["% this command was inserted by lyx2lyx"])
1641         add_to_preamble(document, ["\\usepackage{mathrsfs}"])
1642         break
1643       if i == end:
1644         break
1645       i += 1
1646
1647
1648 def convert_flexnames(document):
1649     "Convert \\begin_inset Flex Custom:Style to \\begin_inset Flex Style and similarly for CharStyle and Element."
1650     
1651     i = 0
1652     rx = re.compile(r'^\\begin_inset Flex (?:Custom|CharStyle|Element):(.+)$')
1653     while True:
1654       i = find_token(document.body, "\\begin_inset Flex", i)
1655       if i == -1:
1656         return
1657       m = rx.match(document.body[i])
1658       if m:
1659         document.body[i] = "\\begin_inset Flex " + m.group(1)
1660       i += 1
1661
1662
1663 flex_insets = [
1664   ["Alert", "CharStyle:Alert"],
1665   ["Code", "CharStyle:Code"],
1666   ["Concepts", "CharStyle:Concepts"],
1667   ["E-Mail", "CharStyle:E-Mail"],
1668   ["Emph", "CharStyle:Emph"],
1669   ["Expression", "CharStyle:Expression"],
1670   ["Initial", "CharStyle:Initial"],
1671   ["Institute", "CharStyle:Institute"],
1672   ["Meaning", "CharStyle:Meaning"],
1673   ["Noun", "CharStyle:Noun"],
1674   ["Strong", "CharStyle:Strong"],
1675   ["Structure", "CharStyle:Structure"],
1676   ["ArticleMode", "Custom:ArticleMode"],
1677   ["Endnote", "Custom:Endnote"],
1678   ["Glosse", "Custom:Glosse"],
1679   ["PresentationMode", "Custom:PresentationMode"],
1680   ["Tri-Glosse", "Custom:Tri-Glosse"]
1681 ]
1682
1683 flex_elements = [
1684   ["Abbrev", "Element:Abbrev"],
1685   ["CCC-Code", "Element:CCC-Code"],
1686   ["Citation-number", "Element:Citation-number"],
1687   ["City", "Element:City"],
1688   ["Code", "Element:Code"],
1689   ["CODEN", "Element:CODEN"],
1690   ["Country", "Element:Country"],
1691   ["Day", "Element:Day"],
1692   ["Directory", "Element:Directory"],
1693   ["Dscr", "Element:Dscr"],
1694   ["Email", "Element:Email"],
1695   ["Emph", "Element:Emph"],
1696   ["Filename", "Element:Filename"],
1697   ["Firstname", "Element:Firstname"],
1698   ["Fname", "Element:Fname"],
1699   ["GuiButton", "Element:GuiButton"],
1700   ["GuiMenu", "Element:GuiMenu"],
1701   ["GuiMenuItem", "Element:GuiMenuItem"],
1702   ["ISSN", "Element:ISSN"],
1703   ["Issue-day", "Element:Issue-day"],
1704   ["Issue-months", "Element:Issue-months"],
1705   ["Issue-number", "Element:Issue-number"],
1706   ["KeyCap", "Element:KeyCap"],
1707   ["KeyCombo", "Element:KeyCombo"],
1708   ["Keyword", "Element:Keyword"],
1709   ["Literal", "Element:Literal"],
1710   ["MenuChoice", "Element:MenuChoice"],
1711   ["Month", "Element:Month"],
1712   ["Orgdiv", "Element:Orgdiv"],
1713   ["Orgname", "Element:Orgname"],
1714   ["Postcode", "Element:Postcode"],
1715   ["SS-Code", "Element:SS-Code"],
1716   ["SS-Title", "Element:SS-Title"],
1717   ["State", "Element:State"],
1718   ["Street", "Element:Street"],
1719   ["Surname", "Element:Surname"],
1720   ["Volume", "Element:Volume"],
1721   ["Year", "Element:Year"]
1722 ]
1723
1724
1725 def revert_flexnames(document):
1726   if document.backend == "latex":
1727     flexlist = flex_insets
1728   else:
1729     flexlist = flex_elements
1730   
1731   rx = re.compile(r'^\\begin_inset Flex\s+(.+)$')
1732   i = 0
1733   while True:
1734     i = find_token(document.body, "\\begin_inset Flex", i)
1735     if i == -1:
1736       return
1737     m = rx.match(document.body[i])
1738     if not m:
1739       document.warning("Illegal flex inset: " + document.body[i])
1740       i += 1
1741       continue
1742     
1743     style = m.group(1)
1744     for f in flexlist:
1745       if f[0] == style:
1746         document.body[i] = "\\begin_inset Flex " + f[1]
1747         break
1748
1749     i += 1
1750
1751
1752 def convert_mathdots(document):
1753     " Load mathdots automatically "
1754     while True:
1755       i = find_token(document.header, "\\use_esint" , 0)
1756       if i != -1:
1757         document.header.insert(i + 1, "\\use_mathdots 1")
1758       break
1759
1760
1761 def revert_mathdots(document):
1762     " Load mathdots if used in the document "
1763     i = 0
1764     ddots = re.compile(r'\\begin_inset Formula .*\\ddots', re.DOTALL)
1765     vdots = re.compile(r'\\begin_inset Formula .*\\vdots', re.DOTALL)
1766     iddots = re.compile(r'\\begin_inset Formula .*\\iddots', re.DOTALL)
1767     mathdots = find_token(document.header, "\\use_mathdots" , 0)
1768     no = find_token(document.header, "\\use_mathdots 0" , 0)
1769     auto = find_token(document.header, "\\use_mathdots 1" , 0)
1770     yes = find_token(document.header, "\\use_mathdots 2" , 0)
1771     if mathdots != -1:
1772       del document.header[mathdots]
1773     while True:
1774       i = find_token(document.body, '\\begin_inset Formula', i)
1775       if i == -1:
1776         return
1777       j = find_end_of_inset(document.body, i)
1778       if j == -1:
1779         document.warning("Malformed LyX document: Can't find end of Formula inset.")
1780         return 
1781       k = ddots.search("\n".join(document.body[i:j]))
1782       l = vdots.search("\n".join(document.body[i:j]))
1783       m = iddots.search("\n".join(document.body[i:j]))
1784       if (yes == -1) and ((no != -1) or (not k and not l and not m) or (auto != -1 and not m)):
1785         i += 1
1786         continue
1787       # use \@ifundefined to catch also the "auto" case
1788       add_to_preamble(document, ["% this command was inserted by lyx2lyx"])
1789       add_to_preamble(document, ["\\@ifundefined{iddots}{\\usepackage{mathdots}}\n"])
1790       return
1791
1792
1793 def convert_rule(document):
1794     " Convert \\lyxline to CommandInset line "
1795     i = 0
1796     while True:
1797       i = find_token(document.body, "\\lyxline" , i)
1798       if i == -1:
1799         return
1800         
1801       j = find_token(document.body, "\\color" , i - 2)
1802       if j == i - 2:
1803         color = document.body[j] + '\n'
1804       else:
1805         color = ''
1806       k = find_token(document.body, "\\begin_layout Standard" , i - 4)
1807       # we need to handle the case that \lyxline is in a separate paragraph and that it is colored
1808       # the result is then an extra empty paragraph which we get by adding an empty ERT inset
1809       if k == i - 4 and j == i - 2 and document.body[i - 1] == '':
1810         layout = '\\begin_inset ERT\nstatus collapsed\n\n\\begin_layout Plain Layout\n\n\n\\end_layout\n\n\\end_inset\n' \
1811           + '\\end_layout\n\n' \
1812           + '\\begin_layout Standard\n'
1813       elif k == i - 2 and document.body[i - 1] == '':
1814         layout = ''
1815       else:
1816         layout = '\\end_layout\n\n' \
1817           + '\\begin_layout Standard\n'
1818       l = find_token(document.body, "\\begin_layout Standard" , i + 4)
1819       if l == i + 4 and document.body[i + 1] == '':
1820         layout2 = ''
1821       else:
1822         layout2 = '\\end_layout\n' \
1823           + '\n\\begin_layout Standard\n'
1824       subst = layout \
1825         + '\\noindent\n\n' \
1826         + color \
1827         + '\\begin_inset CommandInset line\n' \
1828         + 'LatexCommand rule\n' \
1829         + 'offset "0.5ex"\n' \
1830         + 'width "100line%"\n' \
1831         + 'height "1pt"\n' \
1832         + '\n\\end_inset\n\n\n' \
1833         + layout2
1834       document.body[i] = subst
1835       i += 1
1836
1837
1838 def revert_rule(document):
1839     " Revert line insets to Tex code "
1840     i = 0
1841     while 1:
1842       i = find_token(document.body, "\\begin_inset CommandInset line" , i)
1843       if i == -1:
1844         return
1845       # find end of inset
1846       j = find_token(document.body, "\\end_inset" , i)
1847       # assure we found the end_inset of the current inset
1848       if j > i + 6 or j == -1:
1849         document.warning("Malformed LyX document: Can't find end of line inset.")
1850         return
1851       # determine the optional offset
1852       k = find_token(document.body, 'offset', i, j)
1853       if k != -1:
1854         offset = document.body[k][8:-1]
1855       else:
1856         offset = ""
1857       # determine the width
1858       l = find_token(document.body, 'width', i, j)
1859       if l != -1:
1860         width = document.body[l][7:-1]
1861       else:
1862         width = "100col%"
1863       # determine the height
1864       m = find_token(document.body, 'height', i, j)
1865       if m != -1:
1866         height = document.body[m][8:-1]
1867       else:
1868         height = "1pt"
1869       # output the \rule command
1870       if offset:
1871         subst = "\\rule[" + offset + "]{" + width + "}{" + height + "}"
1872       else:
1873         subst = "\\rule{" + width + "}{" + height + "}"
1874       document.body[i:j + 1] = put_cmd_in_ert(subst)
1875       i += 1
1876
1877
1878 def revert_diagram(document):
1879   " Add the feyn package if \\Diagram is used in math "
1880   i = 0
1881   re_diagram = re.compile(r'\\begin_inset Formula .*\\Diagram', re.DOTALL)
1882   while True:
1883     i = find_token(document.body, '\\begin_inset Formula', i)
1884     if i == -1:
1885       return
1886     j = find_end_of_inset(document.body, i)
1887     if j == -1:
1888         document.warning("Malformed LyX document: Can't find end of Formula inset.")
1889         return 
1890     m = re_diagram.search("\n".join(document.body[i:j]))
1891     if not m:
1892       i += 1
1893       continue
1894     add_to_preamble(document, ["% this command was inserted by lyx2lyx"])
1895     add_to_preamble(document, "\\usepackage{feyn}")
1896     # only need to do it once!
1897     return
1898
1899
1900 def convert_bibtex_clearpage(document):
1901   " insert a clear(double)page bibliographystyle if bibtotoc option is used "
1902
1903   i = find_token(document.header, '\\papersides', 0)
1904   if i == -1:
1905     document.warning("Malformed LyX document: Can't find papersides definition.")
1906     return
1907   sides = int(document.header[i][12])
1908
1909   j = 0
1910   while True:
1911     j = find_token(document.body, "\\begin_inset CommandInset bibtex", j)
1912     if j == -1:
1913       return
1914
1915     k = find_end_of_inset(document.body, j)
1916     if k == -1:
1917       document.warning("Can't find end of Bibliography inset at line " + str(j))
1918       j += 1
1919       continue
1920
1921     # only act if there is the option "bibtotoc"
1922     m = find_token(document.body, 'options', j, k)
1923     if m == -1:
1924       document.warning("Can't find options for bibliography inset at line " + str(j))
1925       j = k
1926       continue
1927     
1928     optline = document.body[m]
1929     idx = optline.find("bibtotoc")
1930     if idx == -1:
1931       j = k
1932       continue
1933     
1934     # so we want to insert a new page right before the paragraph that
1935     # this bibliography thing is in. we'll look for it backwards.
1936     lay = j - 1
1937     while lay >= 0:
1938       if document.body[lay].startswith("\\begin_layout"):
1939         break
1940       lay -= 1
1941
1942     if lay < 0:
1943       document.warning("Can't find layout containing bibliography inset at line " + str(j))
1944       j = k
1945       continue
1946
1947     subst1 = '\\begin_layout Standard\n' \
1948       + '\\begin_inset Newpage clearpage\n' \
1949       + '\\end_inset\n\n\n' \
1950       + '\\end_layout\n'
1951     subst2 = '\\begin_layout Standard\n' \
1952       + '\\begin_inset Newpage cleardoublepage\n' \
1953       + '\\end_inset\n\n\n' \
1954       + '\\end_layout\n'
1955     if sides == 1:
1956       document.body.insert(lay, subst1)
1957       document.warning(subst1)
1958     else:
1959       document.body.insert(lay, subst2)
1960       document.warning(subst2)
1961
1962     j = k
1963
1964
1965 ##
1966 # Conversion hub
1967 #
1968
1969 supported_versions = ["2.0.0","2.0"]
1970 convert = [[346, []],
1971            [347, []],
1972            [348, []],
1973            [349, []],
1974            [350, []],
1975            [351, []],
1976            [352, [convert_splitindex]],
1977            [353, []],
1978            [354, []],
1979            [355, []],
1980            [356, []],
1981            [357, []],
1982            [358, []],
1983            [359, [convert_nomencl_width]],
1984            [360, []],
1985            [361, []],
1986            [362, []],
1987            [363, []],
1988            [364, []],
1989            [365, []],
1990            [366, []],
1991            [367, []],
1992            [368, []],
1993            [369, [convert_author_id]],
1994            [370, []],
1995            [371, []],
1996            [372, []],
1997            [373, [merge_gbrief]],
1998            [374, []],
1999            [375, []],
2000            [376, []],
2001            [377, []],
2002            [378, []],
2003            [379, [convert_math_output]],
2004            [380, []],
2005            [381, []],
2006            [382, []],
2007            [383, []],
2008            [384, []],
2009            [385, []],
2010            [386, []],
2011            [387, []],
2012            [388, []],
2013            [389, [convert_html_quotes]],
2014            [390, []],
2015            [391, []],
2016            [392, []],
2017            [393, [convert_optarg]],
2018            [394, [convert_use_makebox]],
2019            [395, []],
2020            [396, []],
2021            [397, [remove_Nameref]],
2022            [398, []],
2023            [399, [convert_mathdots]],
2024            [400, [convert_rule]],
2025            [401, []],
2026            [402, [convert_bibtex_clearpage]],
2027            [403, [convert_flexnames]],
2028            [404, [convert_prettyref]]
2029 ]
2030
2031 revert =  [[403, [revert_refstyle]],
2032            [402, [revert_flexnames]],
2033            [401, []],
2034            [400, [revert_diagram]],
2035            [399, [revert_rule]],
2036            [398, [revert_mathdots]],
2037            [397, [revert_mathrsfs]],
2038            [396, []],
2039            [395, [revert_nameref]],
2040            [394, [revert_DIN_C_pagesizes]],
2041            [393, [revert_makebox]],
2042            [392, [revert_argument]],
2043            [391, []],
2044            [390, [revert_align_decimal, revert_IEEEtran]],
2045            [389, [revert_output_sync]],
2046            [388, [revert_html_quotes]],
2047            [387, [revert_pagesizes]],
2048            [386, [revert_math_scale]],
2049            [385, [revert_lyx_version]],
2050            [384, [revert_shadedboxcolor]],
2051            [383, [revert_fontcolor]],
2052            [382, [revert_turkmen]],
2053            [381, [revert_notefontcolor]],
2054            [380, [revert_equalspacing_xymatrix]],
2055            [379, [revert_inset_preview]],
2056            [378, [revert_math_output]],
2057            [377, []],
2058            [376, [revert_multirow]],
2059            [375, [revert_includeall]],
2060            [374, [revert_includeonly]],
2061            [373, [revert_html_options]],
2062            [372, [revert_gbrief]],
2063            [371, [revert_fontenc]],
2064            [370, [revert_mhchem]],
2065            [369, [revert_suppress_date]],
2066            [368, [revert_author_id]],
2067            [367, [revert_hspace_glue_lengths]],
2068            [366, [revert_percent_vspace_lengths, revert_percent_hspace_lengths]],
2069            [365, [revert_percent_skip_lengths]],
2070            [364, [revert_paragraph_indentation]],
2071            [363, [revert_branch_filename]],
2072            [362, [revert_longtable_align]],
2073            [361, [revert_applemac]],
2074            [360, []],
2075            [359, [revert_nomencl_cwidth]],
2076            [358, [revert_nomencl_width]],
2077            [357, [revert_custom_processors]],
2078            [356, [revert_ulinelatex]],
2079            [355, []],
2080            [354, [revert_strikeout]],
2081            [353, [revert_printindexall]],
2082            [352, [revert_subindex]],
2083            [351, [revert_splitindex]],
2084            [350, [revert_backgroundcolor]],
2085            [349, [revert_outputformat]],
2086            [348, [revert_xetex]],
2087            [347, [revert_phantom, revert_hphantom, revert_vphantom]],
2088            [346, [revert_tabularvalign]],
2089            [345, [revert_swiss]]
2090           ]
2091
2092
2093 if __name__ == "__main__":
2094     pass