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