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