1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2008 The LyX Team <lyx-devel@lists.lyx.org>
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 """ Convert files to the file format generated by lyx 1.6"""
25 from parser_tools import find_token, find_end_of, find_tokens, get_value, get_value_string
27 ####################################################################
28 # Private helper functions
30 def find_end_of_inset(lines, i):
31 " Find end of inset, where lines[i] is included."
32 return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
36 # document.body[i] = wrap_insert_ert(...)
37 # wrap_into_ert may returns a multiline string, which should NOT appear
38 # in document.body. Insetad, do something like this:
39 # subst = wrap_inset_ert(...)
40 # subst = subst.split('\n')
41 # document.body[i:i+1] = subst
43 # where the last statement resets the counter to accord with the added
45 def wrap_into_ert(string, src, dst):
46 " Wrap a something into an ERT"
47 return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
48 + dst + '\n\\end_layout\n\\end_inset\n')
50 def add_to_preamble(document, text):
51 """ Add text to the preamble if it is not already there.
52 Only the first line is checked!"""
54 if find_token(document.preamble, text[0], 0) != -1:
57 document.preamble.extend(text)
59 # Convert a LyX length into a LaTeX length
61 units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
62 "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
63 "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
65 # Convert LyX units to LaTeX units
66 for unit in units.keys():
67 if len.find(unit) != -1:
68 len = '%f' % (len2value(len) / 100)
69 len = len.strip('0') + units[unit]
74 # Return the value of len without the unit in numerical form.
76 result = re.search('([+-]?[0-9.]+)', len)
78 return float(result.group(1))
82 # Unfortunately, this doesn't really work, since Standard isn't always default.
83 # But it's as good as we can do right now.
84 def find_default_layout(document, start, end):
85 l = find_token(document.body, "\\begin_layout Standard", start, end)
87 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
89 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
92 def get_option(document, m, option, default):
93 l = document.body[m].find(option)
96 val = document.body[m][l:].split('"')[1]
99 def remove_option(document, m, option):
100 l = document.body[m].find(option)
102 val = document.body[m][l:].split('"')[1]
103 document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
106 def set_option(document, m, option, value):
107 l = document.body[m].find(option)
109 oldval = document.body[m][l:].split('"')[1]
110 l = l + len(option + '="')
111 document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
113 document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
117 ####################################################################
119 def convert_ltcaption(document):
122 i = find_token(document.body, "\\begin_inset Tabular", i)
125 j = find_end_of_inset(document.body, i + 1)
127 document.warning("Malformed LyX document: Could not find end of tabular.")
130 nrows = int(document.body[i+1].split('"')[3])
131 ncols = int(document.body[i+1].split('"')[5])
134 for k in range(nrows):
135 m = find_token(document.body, "<row", m)
138 for k in range(ncols):
139 m = find_token(document.body, "<cell", m)
141 mend = find_token(document.body, "</cell>", m + 1)
142 # first look for caption insets
143 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
144 # then look for ERT captions
146 mcap = find_token(document.body, "caption", m + 1, mend)
148 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
151 if caption == 'true':
153 set_option(document, r, 'caption', 'true')
154 set_option(document, m, 'multicolumn', '1')
155 set_option(document, m, 'bottomline', 'false')
156 set_option(document, m, 'topline', 'false')
157 set_option(document, m, 'rightline', 'false')
158 set_option(document, m, 'leftline', 'false')
159 #j = find_end_of_inset(document.body, j + 1)
161 set_option(document, m, 'multicolumn', '2')
168 #FIXME Use of wrap_into_ert can confuse lyx2lyx
169 def revert_ltcaption(document):
172 i = find_token(document.body, "\\begin_inset Tabular", i)
175 j = find_end_of_inset(document.body, i + 1)
177 document.warning("Malformed LyX document: Could not find end of tabular.")
181 nrows = int(document.body[i+1].split('"')[3])
182 ncols = int(document.body[i+1].split('"')[5])
184 for k in range(nrows):
185 m = find_token(document.body, "<row", m)
186 caption = get_option(document, m, 'caption', 'false')
187 if caption == 'true':
188 remove_option(document, m, 'caption')
189 for k in range(ncols):
190 m = find_token(document.body, "<cell", m)
191 remove_option(document, m, 'multicolumn')
193 m = find_token(document.body, "\\begin_inset Caption", m)
196 m = find_end_of_inset(document.body, m + 1)
197 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
203 def convert_tablines(document):
206 i = find_token(document.body, "\\begin_inset Tabular", i)
208 # LyX 1.3 inserted an extra space between \begin_inset
209 # and Tabular so let us try if this is the case and fix it.
210 i = find_token(document.body, "\\begin_inset Tabular", i)
214 document.body[i] = "\\begin_inset Tabular"
215 j = find_end_of_inset(document.body, i + 1)
217 document.warning("Malformed LyX document: Could not find end of tabular.")
221 nrows = int(document.body[i+1].split('"')[3])
222 ncols = int(document.body[i+1].split('"')[5])
225 for k in range(ncols):
226 m = find_token(document.body, "<column", m)
227 left = get_option(document, m, 'leftline', 'false')
228 right = get_option(document, m, 'rightline', 'false')
229 col_info.append([left, right])
230 remove_option(document, m, 'leftline')
231 remove_option(document, m, 'rightline')
235 for k in range(nrows):
236 m = find_token(document.body, "<row", m)
237 top = get_option(document, m, 'topline', 'false')
238 bottom = get_option(document, m, 'bottomline', 'false')
239 row_info.append([top, bottom])
240 remove_option(document, m, 'topline')
241 remove_option(document, m, 'bottomline')
246 for k in range(nrows*ncols):
247 m = find_token(document.body, "<cell", m)
248 mc_info.append(get_option(document, m, 'multicolumn', '0'))
251 for l in range(nrows):
252 for k in range(ncols):
253 m = find_token(document.body, '<cell', m)
254 if mc_info[l*ncols + k] == '0':
255 r = set_option(document, m, 'topline', row_info[l][0])
256 r = set_option(document, m, 'bottomline', row_info[l][1])
257 r = set_option(document, m, 'leftline', col_info[k][0])
258 r = set_option(document, m, 'rightline', col_info[k][1])
259 elif mc_info[l*ncols + k] == '1':
261 while s < ncols and mc_info[l*ncols + s] == '2':
263 if s < ncols and mc_info[l*ncols + s] != '1':
264 r = set_option(document, m, 'rightline', col_info[k][1])
265 if k > 0 and mc_info[l*ncols + k - 1] == '0':
266 r = set_option(document, m, 'leftline', col_info[k][0])
271 def revert_tablines(document):
274 i = find_token(document.body, "\\begin_inset Tabular", i)
277 j = find_end_of_inset(document.body, i + 1)
279 document.warning("Malformed LyX document: Could not find end of tabular.")
283 nrows = int(document.body[i+1].split('"')[3])
284 ncols = int(document.body[i+1].split('"')[5])
287 for k in range(nrows*ncols):
288 m = find_token(document.body, "<cell", m)
289 top = get_option(document, m, 'topline', 'false')
290 bottom = get_option(document, m, 'bottomline', 'false')
291 left = get_option(document, m, 'leftline', 'false')
292 right = get_option(document, m, 'rightline', 'false')
293 lines.append([top, bottom, left, right])
296 # we will want to ignore longtable captions
299 for k in range(nrows):
300 m = find_token(document.body, "<row", m)
301 caption = get_option(document, m, 'caption', 'false')
302 caption_info.append([caption])
307 for k in range(ncols):
308 m = find_token(document.body, "<column", m)
310 for l in range(nrows):
311 left = lines[l*ncols + k][2]
312 if left == 'false' and caption_info[l] == 'false':
314 set_option(document, m, 'leftline', left)
316 for l in range(nrows):
317 right = lines[l*ncols + k][3]
318 if right == 'false' and caption_info[l] == 'false':
320 set_option(document, m, 'rightline', right)
324 for k in range(nrows):
325 m = find_token(document.body, "<row", m)
327 for l in range(ncols):
328 top = lines[k*ncols + l][0]
331 if caption_info[k] == 'false':
333 set_option(document, m, 'topline', top)
335 for l in range(ncols):
336 bottom = lines[k*ncols + l][1]
337 if bottom == 'false':
339 if caption_info[k] == 'false':
341 set_option(document, m, 'bottomline', bottom)
347 def fix_wrong_tables(document):
350 i = find_token(document.body, "\\begin_inset Tabular", i)
353 j = find_end_of_inset(document.body, i + 1)
355 document.warning("Malformed LyX document: Could not find end of tabular.")
359 nrows = int(document.body[i+1].split('"')[3])
360 ncols = int(document.body[i+1].split('"')[5])
362 for l in range(nrows):
364 for k in range(ncols):
365 m = find_token(document.body, '<cell', m)
367 if document.body[m].find('multicolumn') != -1:
368 multicol_cont = int(document.body[m].split('"')[1])
370 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
371 document.body[m] = document.body[m][:5] + document.body[m][21:]
374 prev_multicolumn = multicol_cont
381 def close_begin_deeper(document):
385 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
390 if document.body[i][:13] == "\\begin_deeper":
397 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
400 def long_charstyle_names(document):
403 i = find_token(document.body, "\\begin_inset CharStyle", i)
406 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
409 def revert_long_charstyle_names(document):
412 i = find_token(document.body, "\\begin_inset CharStyle", i)
415 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle")
419 def axe_show_label(document):
422 i = find_token(document.body, "\\begin_inset CharStyle", i)
425 if document.body[i + 1].find("show_label") != -1:
426 if document.body[i + 1].find("true") != -1:
427 document.body[i + 1] = "status open"
428 del document.body[ i + 2]
430 if document.body[i + 1].find("false") != -1:
431 document.body[i + 1] = "status collapsed"
432 del document.body[ i + 2]
434 document.warning("Malformed LyX document: show_label neither false nor true.")
436 document.warning("Malformed LyX document: show_label missing in CharStyle.")
441 def revert_show_label(document):
444 i = find_token(document.body, "\\begin_inset CharStyle", i)
447 if document.body[i + 1].find("status open") != -1:
448 document.body.insert(i + 1, "show_label true")
450 if document.body[i + 1].find("status collapsed") != -1:
451 document.body.insert(i + 1, "show_label false")
453 document.warning("Malformed LyX document: no legal status line in CharStyle.")
456 def revert_begin_modules(document):
459 i = find_token(document.header, "\\begin_modules", i)
462 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
464 # this should not happen
466 document.header[i : j + 1] = []
468 def convert_flex(document):
469 "Convert CharStyle to Flex"
472 i = find_token(document.body, "\\begin_inset CharStyle", i)
475 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
477 def revert_flex(document):
478 "Convert Flex to CharStyle"
481 i = find_token(document.body, "\\begin_inset Flex", i)
484 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
487 # Discard PDF options for hyperref
488 def revert_pdf_options(document):
489 "Revert PDF options for hyperref."
490 # store the PDF options and delete the entries from the Lyx file
498 bookmarksnumbered = ""
500 bookmarksopenlevel = ""
508 i = find_token(document.header, "\\use_hyperref", i)
510 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
511 del document.header[i]
512 i = find_token(document.header, "\\pdf_store_options", i)
514 del document.header[i]
515 i = find_token(document.header, "\\pdf_title", 0)
517 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
518 title = ' pdftitle={' + title + '}'
519 del document.header[i]
520 i = find_token(document.header, "\\pdf_author", 0)
522 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
524 author = ' pdfauthor={' + author + '}'
526 author = ',\n pdfauthor={' + author + '}'
527 del document.header[i]
528 i = find_token(document.header, "\\pdf_subject", 0)
530 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
531 if title == "" and author == "":
532 subject = ' pdfsubject={' + subject + '}'
534 subject = ',\n pdfsubject={' + subject + '}'
535 del document.header[i]
536 i = find_token(document.header, "\\pdf_keywords", 0)
538 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
539 if title == "" and author == "" and subject == "":
540 keywords = ' pdfkeywords={' + keywords + '}'
542 keywords = ',\n pdfkeywords={' + keywords + '}'
543 del document.header[i]
544 i = find_token(document.header, "\\pdf_bookmarks", 0)
546 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
547 bookmarks = ',\n bookmarks=' + bookmarks
548 del document.header[i]
549 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
551 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
552 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
553 del document.header[i]
554 i = find_token(document.header, "\\pdf_bookmarksopen", i)
556 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
557 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
558 del document.header[i]
559 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
561 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
562 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
563 del document.header[i]
564 i = find_token(document.header, "\\pdf_breaklinks", i)
566 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
567 breaklinks = ',\n breaklinks=' + breaklinks
568 del document.header[i]
569 i = find_token(document.header, "\\pdf_pdfborder", i)
571 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
572 if pdfborder == 'true':
573 pdfborder = ',\n pdfborder={0 0 0}'
575 pdfborder = ',\n pdfborder={0 0 1}'
576 del document.header[i]
577 i = find_token(document.header, "\\pdf_colorlinks", i)
579 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
580 colorlinks = ',\n colorlinks=' + colorlinks
581 del document.header[i]
582 i = find_token(document.header, "\\pdf_backref", i)
584 backref = get_value_string(document.header, '\\pdf_backref', 0)
585 backref = ',\n backref=' + backref
586 del document.header[i]
587 i = find_token(document.header, "\\pdf_pagebackref", i)
589 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
590 pagebackref = ',\n pagebackref=' + pagebackref
591 del document.header[i]
592 i = find_token(document.header, "\\pdf_pagemode", 0)
594 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
595 pagemode = ',\n pdfpagemode=' + pagemode
596 del document.header[i]
597 i = find_token(document.header, "\\pdf_quoted_options", 0)
599 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
600 if title == "" and author == "" and subject == "" and keywords == "":
601 otheroptions = ' ' + otheroptions
603 otheroptions = ',\n ' + otheroptions
604 del document.header[i]
606 # write to the preamble when hyperref was used
608 # preamble write preparations
609 # bookmark numbers are only output when they are turned on
610 if bookmarksopen == ',\n bookmarksopen=true':
611 bookmarksopen = bookmarksopen + bookmarksopenlevel
612 if bookmarks == ',\n bookmarks=true':
613 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
615 bookmarks = bookmarks
616 # hypersetup is only output when there are things to be set up
617 setupstart = '\\hypersetup{%\n'
619 if otheroptions == "" and title == "" and author == ""\
620 and subject == "" and keywords == "":
624 add_to_preamble(document,
625 ['% Commands inserted by lyx2lyx for PDF properties',
626 '\\usepackage[unicode=true'
645 def remove_inzip_options(document):
646 "Remove inzipName and embed options from the Graphics inset"
649 i = find_token(document.body, "\\begin_inset Graphics", i)
652 j = find_end_of_inset(document.body, i + 1)
655 document.warning("Malformed LyX document: Could not find end of graphics inset.")
656 # If there's a inzip param, just remove that
657 k = find_token(document.body, "\tinzipName", i + 1, j)
660 # embed option must follow the inzipName option
661 del document.body[k+1]
665 def convert_inset_command(document):
668 \begin_inset LatexCommand cmd
670 \begin_inset CommandInset InsetType
675 i = find_token(document.body, "\\begin_inset LatexCommand", i)
678 line = document.body[i]
679 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
683 #this is adapted from factory.cpp
684 if cmdName[0:4].lower() == "cite":
685 insetName = "citation"
686 elif cmdName == "url" or cmdName == "htmlurl":
688 elif cmdName[-3:] == "ref":
690 elif cmdName == "tableofcontents":
692 elif cmdName == "printnomenclature":
693 insetName = "nomencl_print"
694 elif cmdName == "printindex":
695 insetName = "index_print"
698 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
699 document.body[i : i+1] = insertion
702 def revert_inset_command(document):
705 \begin_inset CommandInset InsetType
708 \begin_inset LatexCommand cmd
709 Some insets may end up being converted to insets earlier versions of LyX
710 will not be able to recognize. Not sure what to do about that.
714 i = find_token(document.body, "\\begin_inset CommandInset", i)
717 nextline = document.body[i+1]
718 r = re.compile(r'LatexCommand\s+(.*)$')
719 m = r.match(nextline)
721 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
724 insertion = ["\\begin_inset LatexCommand " + cmdName]
725 document.body[i : i+2] = insertion
728 def convert_wrapfig_options(document):
729 "Convert optional options for wrap floats (wrapfig)."
730 # adds the tokens "lines", "placement", and "overhang"
733 i = find_token(document.body, "\\begin_inset Wrap figure", i)
736 document.body.insert(i + 1, "lines 0")
737 j = find_token(document.body, "placement", i)
738 # placement can be already set or not; if not, set it
740 document.body.insert(i + 3, "overhang 0col%")
742 document.body.insert(i + 2, "placement o")
743 document.body.insert(i + 3, "overhang 0col%")
747 def revert_wrapfig_options(document):
748 "Revert optional options for wrap floats (wrapfig)."
751 i = find_token(document.body, "lines", i)
754 j = find_token(document.body, "overhang", i+1)
755 if j != i + 2 and j != -1:
756 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float.")
760 del document.body[j-1]
764 # To convert and revert indices, we need to convert between LaTeX
765 # strings and LyXText. Here we do a minimal conversion to prevent
766 # crashes and data loss. Manual patch-up may be needed.
773 def convert_latexcommand_index(document):
774 "Convert from LatexCommand form to collapsable form."
777 i = find_token(document.body, "\\begin_inset CommandInset index", i)
780 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
782 fullcontent = document.body[i + 2][5:]
784 fullcontent = fullcontent[1:-1]
785 document.body[i:i + 3] = ["\\begin_inset Index",
787 "\\begin_layout Standard"]
789 # We are now on the blank line preceding "\end_inset"
790 # We will write the content here, into the inset.
792 # Do the LaTeX --> LyX text conversion
793 for rep in replacements:
794 fullcontent = fullcontent.replace(rep[0], rep[1])
796 fullcontent = wrap_into_ert(fullcontent, r'\"', '"')
798 r = re.compile('^(.*?)(\$.*?\$)(.*)')
799 lines = fullcontent.split('\n')
801 #document.warning("LINE: " + line)
802 #document.warning(str(i) + ":" + document.body[i])
803 #document.warning("LAST: " + document.body[-1])
808 f = m.group(2).replace('\\\\', '\\')
812 s = wrap_into_ert(s, r'\\', '\\backslash')
813 s = wrap_into_ert(s, '{', '{')
814 s = wrap_into_ert(s, '}', '}')
815 subst = s.split('\n')
816 document.body[i:i] = subst
818 document.body.insert(i + 1, "\\begin_inset Formula " + f)
819 document.body.insert(i + 2, "\\end_inset")
821 # Generic, \\ -> \backslash:
822 g = wrap_into_ert(g, r'\\', '\\backslash')
823 g = wrap_into_ert(g, '{', '{')
824 g = wrap_into_ert(g, '}', '}')
825 subst = g.split('\n')
826 document.body[i+1:i+1] = subst
828 document.body.insert(i + 1, "\\end_layout")
831 def revert_latexcommand_index(document):
832 "Revert from collapsable form to LatexCommand form."
835 i = find_token(document.body, "\\begin_inset Index", i)
838 j = find_end_of_inset(document.body, i + 1)
841 del document.body[j - 1]
842 del document.body[j - 2] # \end_layout
843 document.body[i] = "\\begin_inset CommandInset index"
844 document.body[i + 1] = "LatexCommand index"
845 # clean up multiline stuff
848 for k in range(i + 3, j - 2):
849 line = document.body[k]
850 if line.startswith("\\begin_inset ERT"):
851 ert_end = find_end_of_inset(document.body, k + 1)
853 if line.startswith("\\begin_inset Formula"):
855 if line.startswith("\\begin_layout Standard"):
857 if line.startswith("\\begin_layout Plain Layout"):
859 if line.startswith("\\end_layout"):
861 if line.startswith("\\end_inset"):
863 if line.startswith("status collapsed"):
865 if line.startswith("status open"):
867 # a lossless reversion is not possible
868 # try at least to handle some common insets and settings
869 # do not replace inside ERTs
871 # Do the LyX text --> LaTeX conversion
872 for rep in replacements:
873 line = line.replace(rep[1], rep[0])
874 line = line.replace(r'\backslash', r'\textbackslash{}')
875 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
876 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
877 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
878 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
879 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
880 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
881 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
882 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
883 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
885 line = line.replace(r'\backslash', r'\\')
886 content = content + line;
887 document.body[i + 3] = "name " + '"' + content + '"'
888 for k in range(i + 4, j - 2):
889 del document.body[i + 4]
890 document.body.insert(i + 4, "")
891 del document.body[i + 2] # \begin_layout standard
895 def revert_wraptable(document):
896 "Revert wrap table to wrap figure."
899 i = find_token(document.body, "\\begin_inset Wrap table", i)
902 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
906 def revert_vietnamese(document):
907 "Set language Vietnamese to English"
908 # Set document language from Vietnamese to English
910 if document.language == "vietnamese":
911 document.language = "english"
912 i = find_token(document.header, "\\language", 0)
914 document.header[i] = "\\language english"
917 j = find_token(document.body, "\\lang vietnamese", j)
920 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
924 def revert_japanese(document):
925 "Set language japanese-plain to japanese"
926 # Set document language from japanese-plain to japanese
928 if document.language == "japanese-plain":
929 document.language = "japanese"
930 i = find_token(document.header, "\\language", 0)
932 document.header[i] = "\\language japanese"
935 j = find_token(document.body, "\\lang japanese-plain", j)
938 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
942 def revert_japanese_encoding(document):
943 "Set input encoding form EUC-JP-plain to EUC-JP etc."
944 # Set input encoding form EUC-JP-plain to EUC-JP etc.
946 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
948 document.header[i] = "\\inputencoding EUC-JP"
950 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
952 document.header[j] = "\\inputencoding JIS"
954 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
955 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
956 document.header[k] = "\\inputencoding UTF8"
959 def revert_inset_info(document):
960 'Replace info inset with its content'
963 i = find_token(document.body, '\\begin_inset Info', i)
966 j = find_end_of_inset(document.body, i + 1)
969 document.warning("Malformed LyX document: Could not find end of Info inset.")
972 for k in range(i, j+1):
973 if document.body[k].startswith("arg"):
974 arg = document.body[k][3:].strip().strip('"')
975 if document.body[k].startswith("type"):
976 type = document.body[k][4:].strip().strip('"')
977 # I think there is a newline after \\end_inset, which should be removed.
978 if document.body[j + 1].strip() == "":
979 document.body[i : (j + 2)] = [type + ':' + arg]
981 document.body[i : (j + 1)] = [type + ':' + arg]
984 def convert_pdf_options(document):
985 # Set the pdfusetitle tag, delete the pdf_store_options,
986 # set quotes for bookmarksopenlevel"
987 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
989 k = find_token(document.header, "\\use_hyperref", 0)
990 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
991 k = find_token(document.header, "\\pdf_store_options", 0)
993 del document.header[k]
994 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
996 document.header[i] = document.header[i].replace('"', '')
999 def revert_pdf_options_2(document):
1000 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1001 k = find_token(document.header, "\\use_hyperref", 0)
1002 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1004 del document.header[i]
1005 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1007 values = document.header[i].split()
1008 values[1] = ' "' + values[1] + '"'
1009 document.header[i] = ''.join(values)
1012 def convert_htmlurl(document):
1013 'Convert "htmlurl" to "href" insets for docbook'
1014 if document.backend != "docbook":
1018 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1021 document.body[i] = "\\begin_inset CommandInset href"
1022 document.body[i + 1] = "LatexCommand href"
1026 def convert_url(document):
1027 'Convert url insets to url charstyles'
1028 if document.backend == "docbook":
1032 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1035 n = find_token(document.body, "name", i)
1037 # place the URL name in typewriter before the new URL insert
1038 # grab the name 'bla' from the e.g. the line 'name "bla"',
1039 # therefore start with the 6th character
1040 name = document.body[n][6:-1]
1041 newname = [name + " "]
1042 document.body[i:i] = newname
1044 j = find_token(document.body, "target", i)
1046 document.warning("Malformed LyX document: Can't find target for url inset")
1049 target = document.body[j][8:-1]
1050 k = find_token(document.body, "\\end_inset", j)
1052 document.warning("Malformed LyX document: Can't find end of url inset")
1055 newstuff = ["\\begin_inset Flex URL",
1056 "status collapsed", "",
1057 "\\begin_layout Standard",
1062 document.body[i:k] = newstuff
1065 def convert_ams_classes(document):
1066 tc = document.textclass
1067 if (tc != "amsart" and tc != "amsart-plain" and
1068 tc != "amsart-seq" and tc != "amsbook"):
1070 if tc == "amsart-plain":
1071 document.textclass = "amsart"
1072 document.set_textclass()
1073 document.add_module("Theorems (Starred)")
1075 if tc == "amsart-seq":
1076 document.textclass = "amsart"
1077 document.set_textclass()
1078 document.add_module("Theorems (AMS)")
1080 #Now we want to see if any of the environments in the extended theorems
1081 #module were used in this document. If so, we'll add that module, too.
1082 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1083 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1086 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1089 i = find_token(document.body, "\\begin_layout", i)
1092 m = r.match(document.body[i])
1094 document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1098 if layouts.count(m) != 0:
1099 document.add_module("Theorems (AMS-Extended)")
1103 def revert_href(document):
1104 'Reverts hyperlink insets (href) to url insets (url)'
1107 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1110 document.body[i : i + 2] = \
1111 ["\\begin_inset CommandInset url", "LatexCommand url"]
1115 def convert_include(document):
1116 'Converts include insets to new format.'
1118 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1120 i = find_token(document.body, "\\begin_inset Include", i)
1123 line = document.body[i]
1124 previewline = document.body[i + 1]
1127 document.warning("Unable to match line " + str(i) + " of body!")
1133 insertion = ["\\begin_inset CommandInset include",
1134 "LatexCommand " + cmd, previewline,
1135 "filename \"" + fn + "\""]
1138 insertion.append("lstparams " + '"' + opt + '"')
1140 document.body[i : i + 2] = insertion
1144 def revert_include(document):
1145 'Reverts include insets to old format.'
1147 r1 = re.compile('LatexCommand (.+)')
1148 r2 = re.compile('filename (.+)')
1149 r3 = re.compile('options (.*)')
1151 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1154 previewline = document.body[i + 1]
1155 m = r1.match(document.body[i + 2])
1157 document.warning("Malformed LyX document: No LatexCommand line for `" +
1158 document.body[i] + "' on line " + str(i) + ".")
1162 m = r2.match(document.body[i + 3])
1164 document.warning("Malformed LyX document: No filename line for `" + \
1165 document.body[i] + "' on line " + str(i) + ".")
1171 if (cmd == "lstinputlisting"):
1172 m = r3.match(document.body[i + 4])
1174 options = m.group(1)
1176 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1178 newline += ("[" + options + "]")
1179 insertion = [newline, previewline]
1180 document.body[i : i + numlines] = insertion
1184 def revert_albanian(document):
1185 "Set language Albanian to English"
1187 if document.language == "albanian":
1188 document.language = "english"
1189 i = find_token(document.header, "\\language", 0)
1191 document.header[i] = "\\language english"
1194 j = find_token(document.body, "\\lang albanian", j)
1197 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1201 def revert_lowersorbian(document):
1202 "Set language lower Sorbian to English"
1204 if document.language == "lowersorbian":
1205 document.language = "english"
1206 i = find_token(document.header, "\\language", 0)
1208 document.header[i] = "\\language english"
1211 j = find_token(document.body, "\\lang lowersorbian", j)
1214 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1218 def revert_uppersorbian(document):
1219 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1221 if document.language == "uppersorbian":
1222 document.language = "usorbian"
1223 i = find_token(document.header, "\\language", 0)
1225 document.header[i] = "\\language usorbian"
1228 j = find_token(document.body, "\\lang uppersorbian", j)
1231 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1235 def convert_usorbian(document):
1236 "Set language usorbian to uppersorbian"
1238 if document.language == "usorbian":
1239 document.language = "uppersorbian"
1240 i = find_token(document.header, "\\language", 0)
1242 document.header[i] = "\\language uppersorbian"
1245 j = find_token(document.body, "\\lang usorbian", j)
1248 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1252 def revert_macro_optional_params(document):
1253 "Convert macro definitions with optional parameters into ERTs"
1254 # Stub to convert macro definitions with one or more optional parameters
1255 # into uninterpreted ERT insets
1258 def revert_hyperlinktype(document):
1259 'Reverts hyperlink type'
1263 i = find_token(document.body, "target", i)
1266 j = find_token(document.body, "type", i)
1270 del document.body[j]
1274 def revert_pagebreak(document):
1275 'Reverts pagebreak to ERT'
1278 i = find_token(document.body, "\\pagebreak", i)
1281 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1282 '\\begin_layout Standard\n\n\n\\backslash\n' \
1283 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1287 def revert_linebreak(document):
1288 'Reverts linebreak to ERT'
1291 i = find_token(document.body, "\\linebreak", i)
1294 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1295 '\\begin_layout Standard\n\n\n\\backslash\n' \
1296 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1300 def revert_latin(document):
1301 "Set language Latin to English"
1303 if document.language == "latin":
1304 document.language = "english"
1305 i = find_token(document.header, "\\language", 0)
1307 document.header[i] = "\\language english"
1310 j = find_token(document.body, "\\lang latin", j)
1313 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1317 def revert_samin(document):
1318 "Set language North Sami to English"
1320 if document.language == "samin":
1321 document.language = "english"
1322 i = find_token(document.header, "\\language", 0)
1324 document.header[i] = "\\language english"
1327 j = find_token(document.body, "\\lang samin", j)
1330 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1334 def convert_serbocroatian(document):
1335 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1337 if document.language == "serbocroatian":
1338 document.language = "croatian"
1339 i = find_token(document.header, "\\language", 0)
1341 document.header[i] = "\\language croatian"
1344 j = find_token(document.body, "\\lang serbocroatian", j)
1347 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1351 def convert_framed_notes(document):
1352 "Convert framed notes to boxes. "
1355 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1358 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1367 'height_special "totalheight"']
1368 document.body[i:i+1] = subst
1372 def convert_module_names(document):
1373 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1374 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1375 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1376 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1377 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1378 modlist = document.get_module_list()
1379 if len(modlist) == 0:
1383 if modulemap.has_key(mod):
1384 newmodlist.append(modulemap[mod])
1386 document.warning("Can't find module %s in the module map!" % mod)
1387 newmodlist.append(mod)
1388 document.set_module_list(newmodlist)
1391 def revert_module_names(document):
1392 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1393 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1394 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1395 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1396 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1397 modlist = document.get_module_list()
1398 if len(modlist) == 0:
1402 if modulemap.has_key(mod):
1403 newmodlist.append(modulemap[mod])
1405 document.warning("Can't find module %s in the module map!" % mod)
1406 newmodlist.append(mod)
1407 document.set_module_list(newmodlist)
1410 def revert_colsep(document):
1411 i = find_token(document.header, "\\columnsep", 0)
1414 colsepline = document.header[i]
1415 r = re.compile(r'\\columnsep (.*)')
1416 m = r.match(colsepline)
1418 document.warning("Malformed column separation line!")
1421 del document.header[i]
1422 #it seems to be safe to add the package even if it is already used
1423 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1425 add_to_preamble(document, pretext)
1428 def revert_framed_notes(document):
1429 "Revert framed boxes to notes. "
1432 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1436 j = find_end_of_inset(document.body, i + 1)
1439 document.warning("Malformed LyX document: Could not find end of Box inset.")
1440 k = find_token(document.body, "status", i + 1, j)
1442 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1444 status = document.body[k]
1445 l = find_default_layout(document, i + 1, j)
1447 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1449 m = find_token(document.body, "\\end_layout", i + 1, j)
1451 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1453 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1454 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1455 if ibox == -1 and pbox == -1:
1456 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1457 del document.body[i+1:k]
1459 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1460 subst1 = [document.body[l],
1461 "\\begin_inset Note Shaded",
1463 '\\begin_layout Standard']
1464 document.body[l:l + 1] = subst1
1465 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1466 document.body[m:m + 1] = subst2
1470 def revert_slash(document):
1471 'Revert \\SpecialChar \\slash{} to ERT'
1472 r = re.compile(r'\\SpecialChar \\slash{}')
1474 while i < len(document.body):
1475 m = r.match(document.body[i])
1477 subst = ['\\begin_inset ERT',
1478 'status collapsed', '',
1479 '\\begin_layout Standard',
1480 '', '', '\\backslash',
1484 document.body[i: i+1] = subst
1490 def revert_nobreakdash(document):
1491 'Revert \\SpecialChar \\nobreakdash- to ERT'
1493 while i < len(document.body):
1494 line = document.body[i]
1495 r = re.compile(r'\\SpecialChar \\nobreakdash-')
1498 subst = ['\\begin_inset ERT',
1499 'status collapsed', '',
1500 '\\begin_layout Standard', '', '',
1505 document.body[i:i+1] = subst
1507 j = find_token(document.header, "\\use_amsmath", 0)
1509 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1511 document.header[j] = "\\use_amsmath 2"
1516 #Returns number of lines added/removed
1517 def revert_nocite_key(body, start, end):
1518 'key "..." -> \nocite{...}'
1519 r = re.compile(r'^key "(.*)"')
1523 m = r.match(body[i])
1525 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1526 j += 1 # because we added a line
1527 i += 2 # skip that line
1530 j -= 1 # because we deleted a line
1531 # no need to change i, since it now points to the next line
1535 def revert_nocite(document):
1536 "Revert LatexCommand nocite to ERT"
1539 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1542 if (document.body[i+1] != "LatexCommand nocite"):
1543 # note that we already incremented i
1546 insetEnd = find_end_of_inset(document.body, i)
1548 #this should not happen
1549 document.warning("End of CommandInset citation not found in revert_nocite!")
1552 paramLocation = i + 2 #start of the inset's parameters
1554 document.body[i:i+2] = \
1555 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1556 # that added two lines
1559 #print insetEnd, document.body[i: insetEnd + 1]
1560 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1561 #print insetEnd, document.body[i: insetEnd + 1]
1562 document.body.insert(insetEnd, "\\end_layout")
1563 document.body.insert(insetEnd + 1, "")
1567 def revert_btprintall(document):
1568 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1569 i = find_token(document.header, '\\use_bibtopic', 0)
1571 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1573 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1575 while i < len(document.body):
1576 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1579 j = find_end_of_inset(document.body, i + 1)
1581 #this should not happen
1582 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1583 j = len(document.body)
1584 # this range isn't really right, but it should be OK, since we shouldn't
1585 # see more than one matching line in each inset
1587 for k in range(i, j):
1588 if (document.body[k] == 'btprint "btPrintAll"'):
1589 del document.body[k]
1590 subst = ["\\begin_inset ERT",
1591 "status collapsed", "",
1592 "\\begin_layout Standard", "",
1597 document.body[i:i] = subst
1598 addlines = addedlines + len(subst) - 1
1602 def revert_bahasam(document):
1603 "Set language Bahasa Malaysia to Bahasa Indonesia"
1605 if document.language == "bahasam":
1606 document.language = "bahasa"
1607 i = find_token(document.header, "\\language", 0)
1609 document.header[i] = "\\language bahasa"
1612 j = find_token(document.body, "\\lang bahasam", j)
1615 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1619 def revert_interlingua(document):
1620 "Set language Interlingua to English"
1622 if document.language == "interlingua":
1623 document.language = "english"
1624 i = find_token(document.header, "\\language", 0)
1626 document.header[i] = "\\language english"
1629 j = find_token(document.body, "\\lang interlingua", j)
1632 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1636 def revert_serbianlatin(document):
1637 "Set language Serbian-Latin to Croatian"
1639 if document.language == "serbian-latin":
1640 document.language = "croatian"
1641 i = find_token(document.header, "\\language", 0)
1643 document.header[i] = "\\language croatian"
1646 j = find_token(document.body, "\\lang serbian-latin", j)
1649 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
1653 def revert_rotfloat(document):
1654 " Revert sideways custom floats. "
1657 # whitespace intended (exclude \\begin_inset FloatList)
1658 i = find_token(document.body, "\\begin_inset Float ", i)
1661 line = document.body[i]
1662 r = re.compile(r'\\begin_inset Float (.*)$')
1665 document.warning("Unable to match line " + str(i) + " of body!")
1668 floattype = m.group(1)
1669 if floattype == "figure" or floattype == "table":
1672 j = find_end_of_inset(document.body, i)
1674 document.warning("Malformed lyx document: Missing '\\end_inset'.")
1678 if get_value(document.body, 'sideways', i, j) == "false":
1681 l = find_default_layout(document, i + 1, j)
1683 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1685 subst = ['\\begin_layout Standard',
1686 '\\begin_inset ERT',
1687 'status collapsed', '',
1688 '\\begin_layout Standard', '', '',
1690 'end{sideways' + floattype + '}',
1691 '\\end_layout', '', '\\end_inset']
1692 document.body[j : j+1] = subst
1693 addedLines = len(subst) - 1
1694 del document.body[i+1 : l]
1695 addedLines -= (l-1) - (i+1)
1696 subst = ['\\begin_inset ERT', 'status collapsed', '',
1697 '\\begin_layout Standard', '', '', '\\backslash',
1698 'begin{sideways' + floattype + '}',
1699 '\\end_layout', '', '\\end_inset', '',
1701 document.body[i : i+1] = subst
1702 addedLines += len(subst) - 1
1703 if floattype == "algorithm":
1704 add_to_preamble(document,
1705 ['% Commands inserted by lyx2lyx for sideways algorithm float',
1706 '\\usepackage{rotfloat}',
1707 '\\floatstyle{ruled}',
1708 '\\newfloat{algorithm}{tbp}{loa}',
1709 '\\floatname{algorithm}{Algorithm}'])
1711 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
1715 def revert_widesideways(document):
1716 " Revert wide sideways floats. "
1719 # whitespace intended (exclude \\begin_inset FloatList)
1720 i = find_token(document.body, '\\begin_inset Float ', i)
1723 line = document.body[i]
1724 r = re.compile(r'\\begin_inset Float (.*)$')
1727 document.warning("Unable to match line " + str(i) + " of body!")
1730 floattype = m.group(1)
1731 if floattype != "figure" and floattype != "table":
1734 j = find_end_of_inset(document.body, i)
1736 document.warning("Malformed lyx document: Missing '\\end_inset'.")
1739 if get_value(document.body, 'sideways', i, j) == "false" or \
1740 get_value(document.body, 'wide', i, j) == "false":
1743 l = find_default_layout(document, i + 1, j)
1745 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1747 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
1748 'status collapsed', '',
1749 '\\begin_layout Standard', '', '', '\\backslash',
1750 'end{sideways' + floattype + '*}',
1751 '\\end_layout', '', '\\end_inset']
1752 document.body[j : j+1] = subst
1753 addedLines = len(subst) - 1
1754 del document.body[i+1:l-1]
1755 addedLines -= (l-1) - (i+1)
1756 subst = ['\\begin_inset ERT', 'status collapsed', '',
1757 '\\begin_layout Standard', '', '', '\\backslash',
1758 'begin{sideways' + floattype + '*}', '\\end_layout', '',
1759 '\\end_inset', '', '\\end_layout', '']
1760 document.body[i : i+1] = subst
1761 addedLines += len(subst) - 1
1762 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
1766 def revert_inset_embedding(document, type):
1767 ' Remove embed tag from certain type of insets'
1770 i = find_token(document.body, "\\begin_inset %s" % type, i)
1773 j = find_end_of_inset(document.body, i)
1775 document.warning("Malformed lyx document: Missing '\\end_inset'.")
1778 k = find_token(document.body, "\tembed", i, j)
1780 k = find_token(document.body, "embed", i, j)
1782 del document.body[k]
1786 def revert_external_embedding(document):
1787 ' Remove embed tag from external inset '
1788 revert_inset_embedding(document, 'External')
1791 def convert_subfig(document):
1792 " Convert subfigures to subfloats. "
1795 i = find_token(document.body, '\\begin_inset Graphics', i)
1798 j = find_end_of_inset(document.body, i)
1800 document.warning("Malformed lyx document: Missing '\\end_inset'.")
1803 k = find_token(document.body, '\tsubcaption', i, j)
1807 l = find_token(document.body, '\tsubcaptionText', i, j)
1808 caption = document.body[l][16:].strip('"')
1809 savestr = document.body[i]
1810 laststr = document.body[j]
1811 del document.body[l]
1812 del document.body[k]
1814 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
1815 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset',
1816 'Caption', '', '\\begin_layout Plain Layout',
1817 caption, '\\end_layout', '', '\\end_inset', '',
1818 '\\end_layout', '', '\\begin_layout Plain Layout', savestr]
1819 document.body[i : i+1] = subst
1820 addedLines += len(subst) - 1
1821 subst = ['', '\\end_layout', '', '\\end_inset', laststr]
1822 document.body[j : j+1] = subst
1823 addedLines += len(subst) - 1
1827 def revert_subfig(document):
1828 " Revert subfloats. "
1831 # whitespace intended (exclude \\begin_inset FloatList)
1832 i = find_token(document.body, '\\begin_inset Float ', i)
1836 j = find_end_of_inset(document.body, i)
1838 document.warning("Malformed lyx document: Missing '\\end_inset' (float).")
1841 # look for embedded float (= subfloat)
1842 # whitespace intended (exclude \\begin_inset FloatList)
1843 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
1846 l = find_end_of_inset(document.body, k)
1848 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
1851 m = find_default_layout(document, k + 1, l)
1853 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
1857 capend = find_end_of_inset(document.body, cap)
1859 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
1863 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
1865 lblend = find_end_of_inset(document.body, lbl + 1)
1867 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
1869 for line in document.body[lbl:lblend + 1]:
1870 if line.startswith('name '):
1871 label = line.split()[1].strip('"')
1878 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
1880 optend = find_end_of_inset(document.body, opt)
1882 document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
1884 optc = find_default_layout(document, opt, optend)
1886 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1888 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
1889 for line in document.body[optc:optcend]:
1890 if not line.startswith('\\'):
1891 shortcap += line.strip()
1895 for line in document.body[cap:capend]:
1896 if line in document.body[lbl:lblend]:
1898 elif line in document.body[opt:optend]:
1900 elif not line.startswith('\\'):
1901 caption += line.strip()
1903 caption += "\\backslash\nlabel{" + label + "}"
1904 document.body[l] = '\\begin_layout Plain Layout\n\\begin_inset ERT\nstatus collapsed\n\n' \
1905 '\\begin_layout Plain Layout\n\n}\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n\n\\begin_layout Plain Layout\n'
1906 del document.body[cap:capend+1]
1907 del document.body[k+1:m-1]
1908 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
1909 '\\begin_layout Plain Layout\n\n\\backslash\n' \
1911 if len(shortcap) > 0:
1912 insertion = insertion + "[" + shortcap + "]"
1913 if len(caption) > 0:
1914 insertion = insertion + "[" + caption + "]"
1915 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
1916 document.body[k] = insertion
1917 add_to_preamble(document,
1918 ['\\usepackage{subfig}\n'])
1922 def revert_wrapplacement(document):
1923 " Revert placement options wrap floats (wrapfig). "
1926 i = find_token(document.body, "lines", i)
1929 j = find_token(document.body, "placement", i+1)
1931 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
1933 document.body[j] = document.body[j].replace("placement O", "placement o")
1934 document.body[j] = document.body[j].replace("placement I", "placement i")
1935 document.body[j] = document.body[j].replace("placement L", "placement l")
1936 document.body[j] = document.body[j].replace("placement R", "placement r")
1940 def remove_extra_embedded_files(document):
1941 " Remove \extra_embedded_files from buffer params "
1942 i = find_token(document.header, '\\extra_embedded_files', 0)
1945 document.header.pop(i)
1948 def convert_spaceinset(document):
1949 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
1951 while i < len(document.body):
1952 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
1956 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
1957 document.body[i: i+1] = subst
1963 def revert_spaceinset(document):
1964 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
1967 i = find_token(document.body, "\\begin_inset Space", i)
1970 j = find_end_of_inset(document.body, i)
1972 document.warning("Malformed LyX document: Could not find end of space inset.")
1974 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
1975 del document.body[j]
1978 def convert_hfill(document):
1979 " Convert hfill to space inset "
1982 i = find_token(document.body, "\\hfill", i)
1985 subst = document.body[i].replace('\\hfill', \
1986 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
1987 subst = subst.split('\n')
1988 document.body[i : i+1] = subst
1992 def revert_hfills(document):
1993 ' Revert \\hfill commands '
1994 hfill = re.compile(r'\\hfill')
1995 dotfill = re.compile(r'\\dotfill')
1996 hrulefill = re.compile(r'\\hrulefill')
1999 i = find_token(document.body, "\\InsetSpace", i)
2002 if hfill.search(document.body[i]):
2003 document.body[i] = \
2004 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2007 if dotfill.search(document.body[i]):
2008 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2009 '\\begin_inset ERT\nstatus collapsed\n\n' \
2010 '\\begin_layout Standard\n\n\n\\backslash\n' \
2011 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2012 subst = subst.split('\n')
2013 document.body[i : i+1] = subst
2016 if hrulefill.search(document.body[i]):
2017 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2018 '\\begin_inset ERT\nstatus collapsed\n\n' \
2019 '\\begin_layout Standard\n\n\n\\backslash\n' \
2020 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2021 subst = subst.split('\n')
2022 document.body[i : i+1] = subst
2027 def revert_hspace(document):
2028 ' Revert \\InsetSpace \\hspace{} to ERT '
2030 hspace = re.compile(r'\\hspace{}')
2031 hstar = re.compile(r'\\hspace\*{}')
2033 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2036 length = get_value(document.body, '\\length', i+1)
2038 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2040 del document.body[i+1]
2042 if hstar.search(document.body[i]):
2043 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2044 '\\begin_inset ERT\nstatus collapsed\n\n' \
2045 '\\begin_layout Standard\n\n\n\\backslash\n' \
2046 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2047 subst = subst.split('\n')
2048 document.body[i : i+1] = subst
2049 addedLines += len(subst) - 1
2052 if hspace.search(document.body[i]):
2053 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2054 '\\begin_inset ERT\nstatus collapsed\n\n' \
2055 '\\begin_layout Standard\n\n\n\\backslash\n' \
2056 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2057 subst = subst.split('\n')
2058 document.body[i : i+1] = subst
2059 addedLines += len(subst) - 1
2065 def revert_protected_hfill(document):
2066 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2069 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2072 j = find_end_of_inset(document.body, i)
2074 document.warning("Malformed LyX document: Could not find end of space inset.")
2076 del document.body[j]
2077 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2078 '\\begin_inset ERT\nstatus collapsed\n\n' \
2079 '\\begin_layout Standard\n\n\n\\backslash\n' \
2080 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2081 subst = subst.split('\n')
2082 document.body[i : i+1] = subst
2086 def revert_leftarrowfill(document):
2087 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2090 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2093 j = find_end_of_inset(document.body, i)
2095 document.warning("Malformed LyX document: Could not find end of space inset.")
2097 del document.body[j]
2098 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2099 '\\begin_inset ERT\nstatus collapsed\n\n' \
2100 '\\begin_layout Standard\n\n\n\\backslash\n' \
2101 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2102 subst = subst.split('\n')
2103 document.body[i : i+1] = subst
2107 def revert_rightarrowfill(document):
2108 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2111 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2114 j = find_end_of_inset(document.body, i)
2116 document.warning("Malformed LyX document: Could not find end of space inset.")
2118 del document.body[j]
2119 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2120 '\\begin_inset ERT\nstatus collapsed\n\n' \
2121 '\\begin_layout Standard\n\n\n\\backslash\n' \
2122 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2123 subst = subst.split('\n')
2124 document.body[i : i+1] = subst
2128 def revert_upbracefill(document):
2129 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2132 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2135 j = find_end_of_inset(document.body, i)
2137 document.warning("Malformed LyX document: Could not find end of space inset.")
2139 del document.body[j]
2140 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2141 '\\begin_inset ERT\nstatus collapsed\n\n' \
2142 '\\begin_layout Standard\n\n\n\\backslash\n' \
2143 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2144 subst = subst.split('\n')
2145 document.body[i : i+1] = subst
2149 def revert_downbracefill(document):
2150 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2153 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2156 j = find_end_of_inset(document.body, i)
2158 document.warning("Malformed LyX document: Could not find end of space inset.")
2160 del document.body[j]
2161 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2162 '\\begin_inset ERT\nstatus collapsed\n\n' \
2163 '\\begin_layout Standard\n\n\n\\backslash\n' \
2164 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2165 subst = subst.split('\n')
2166 document.body[i : i+1] = subst
2170 def revert_local_layout(document):
2171 ' Revert local layout headers.'
2174 i = find_token(document.header, "\\begin_local_layout", i)
2177 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2179 # this should not happen
2181 document.header[i : j + 1] = []
2184 def convert_pagebreaks(document):
2185 ' Convert inline Newpage insets to new format '
2188 i = find_token(document.body, '\\newpage', i)
2191 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2195 i = find_token(document.body, '\\pagebreak', i)
2198 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2202 i = find_token(document.body, '\\clearpage', i)
2205 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2209 i = find_token(document.body, '\\cleardoublepage', i)
2212 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2216 def revert_pagebreaks(document):
2217 ' Revert \\begin_inset Newpage to previous inline format '
2220 i = find_token(document.body, '\\begin_inset Newpage', i)
2223 j = find_end_of_inset(document.body, i)
2225 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2227 del document.body[j]
2228 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2229 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2230 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2231 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2234 def convert_linebreaks(document):
2235 ' Convert inline Newline insets to new format '
2238 i = find_token(document.body, '\\newline', i)
2241 document.body[i:i+1] = ['\\begin_inset Newline newline',
2245 i = find_token(document.body, '\\linebreak', i)
2248 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2252 def revert_linebreaks(document):
2253 ' Revert \\begin_inset Newline to previous inline format '
2256 i = find_token(document.body, '\\begin_inset Newline', i)
2259 j = find_end_of_inset(document.body, i)
2261 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2263 del document.body[j]
2264 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2265 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2268 def convert_japanese_plain(document):
2269 ' Set language japanese-plain to japanese '
2271 if document.language == "japanese-plain":
2272 document.language = "japanese"
2273 i = find_token(document.header, "\\language", 0)
2275 document.header[i] = "\\language japanese"
2278 j = find_token(document.body, "\\lang japanese-plain", j)
2281 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2285 def revert_pdfpages(document):
2286 ' Revert pdfpages external inset to ERT '
2289 i = find_token(document.body, "\\begin_inset External", i)
2292 j = find_end_of_inset(document.body, i)
2294 document.warning("Malformed lyx document: Missing '\\end_inset'.")
2297 if get_value(document.body, 'template', i, j) == "PDFPages":
2298 filename = get_value(document.body, 'filename', i, j)
2300 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2301 for k in range(i, j):
2302 m = r.match(document.body[k])
2305 angle = get_value(document.body, 'rotateAngle', i, j)
2306 width = get_value(document.body, 'width', i, j)
2307 height = get_value(document.body, 'height', i, j)
2308 scale = get_value(document.body, 'scale', i, j)
2309 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2313 options += ",angle=" + angle
2315 options += "angle=" + angle
2318 options += ",width=" + convert_len(width)
2320 options += "width=" + convert_len(width)
2323 options += ",height=" + convert_len(height)
2325 options += "height=" + convert_len(height)
2328 options += ",scale=" + scale
2330 options += "scale=" + scale
2331 if keepAspectRatio != '':
2333 options += ",keepaspectratio"
2335 options += "keepaspectratio"
2337 options = '[' + options + ']'
2338 del document.body[i+1:j+1]
2339 document.body[i:i+1] = ['\\begin_inset ERT',
2342 '\\begin_layout Standard',
2345 'includepdf' + options + '{' + filename + '}',
2349 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2355 def revert_mexican(document):
2356 ' Set language Spanish(Mexico) to Spanish '
2358 if document.language == "spanish-mexico":
2359 document.language = "spanish"
2360 i = find_token(document.header, "\\language", 0)
2362 document.header[i] = "\\language spanish"
2365 j = find_token(document.body, "\\lang spanish-mexico", j)
2368 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2372 def remove_embedding(document):
2373 ' Remove embed tag from all insets '
2374 revert_inset_embedding(document, 'Graphics')
2375 revert_inset_embedding(document, 'External')
2376 revert_inset_embedding(document, 'CommandInset include')
2377 revert_inset_embedding(document, 'CommandInset bibtex')
2380 def revert_master(document):
2381 ' Remove master param '
2382 i = find_token(document.header, "\\master", 0)
2384 del document.header[i]
2387 def revert_graphics_group(document):
2388 ' Revert group information from graphics insets '
2391 i = find_token(document.body, "\\begin_inset Graphics", i)
2394 j = find_end_of_inset(document.body, i)
2396 document.warning("Malformed lyx document: Missing '\\end_inset'.")
2399 k = find_token(document.body, " groupId", i, j)
2403 del document.body[k]
2407 def update_apa_styles(document):
2408 ' Replace obsolete styles '
2410 if document.textclass != "apa":
2413 obsoletedby = { "Acknowledgments": "Acknowledgements",
2414 "Section*": "Section",
2415 "Subsection*": "Subsection",
2416 "Subsubsection*": "Subsubsection",
2417 "Paragraph*": "Paragraph",
2418 "Subparagraph*": "Subparagraph"}
2421 i = find_token(document.body, "\\begin_layout", i)
2425 layout = document.body[i][14:]
2426 if layout in obsoletedby:
2427 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2432 def convert_paper_sizes(document):
2433 ' exchange size options legalpaper and executivepaper to correct order '
2434 # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2437 i = find_token(document.header, "\\papersize executivepaper", 0)
2439 document.header[i] = "\\papersize legalpaper"
2441 j = find_token(document.header, "\\papersize legalpaper", 0)
2443 document.header[j] = "\\papersize executivepaper"
2446 def revert_paper_sizes(document):
2447 ' exchange size options legalpaper and executivepaper to correct order '
2450 i = find_token(document.header, "\\papersize executivepaper", 0)
2452 document.header[i] = "\\papersize legalpaper"
2454 j = find_token(document.header, "\\papersize legalpaper", 0)
2456 document.header[j] = "\\papersize executivepaper"
2459 def convert_InsetSpace(document):
2460 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2463 i = find_token(document.body, "\\begin_inset Space", i)
2466 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2469 def revert_InsetSpace(document):
2470 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2473 i = find_token(document.body, "\\begin_inset space", i)
2476 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2483 supported_versions = ["1.6.0","1.6"]
2484 convert = [[277, [fix_wrong_tables]],
2485 [278, [close_begin_deeper]],
2486 [279, [long_charstyle_names]],
2487 [280, [axe_show_label]],
2490 [283, [convert_flex]],
2494 [287, [convert_wrapfig_options]],
2495 [288, [convert_inset_command]],
2496 [289, [convert_latexcommand_index]],
2501 [294, [convert_pdf_options]],
2502 [295, [convert_htmlurl, convert_url]],
2503 [296, [convert_include]],
2504 [297, [convert_usorbian]],
2510 [303, [convert_serbocroatian]],
2511 [304, [convert_framed_notes]],
2518 [311, [convert_ams_classes]],
2520 [313, [convert_module_names]],
2523 [316, [convert_subfig]],
2526 [319, [convert_spaceinset, convert_hfill]],
2528 [321, [convert_tablines]],
2530 [323, [convert_pagebreaks]],
2531 [324, [convert_linebreaks]],
2532 [325, [convert_japanese_plain]],
2535 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
2538 [331, [convert_ltcaption]],
2540 [333, [update_apa_styles]],
2541 [334, [convert_paper_sizes]],
2542 [335, [convert_InsetSpace]],
2545 revert = [[334, [revert_InsetSpace]],
2546 [333, [revert_paper_sizes]],
2548 [331, [revert_graphics_group]],
2549 [330, [revert_ltcaption]],
2550 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
2551 [328, [revert_master]],
2553 [326, [revert_mexican]],
2554 [325, [revert_pdfpages]],
2556 [323, [revert_linebreaks]],
2557 [322, [revert_pagebreaks]],
2558 [321, [revert_local_layout]],
2559 [320, [revert_tablines]],
2560 [319, [revert_protected_hfill]],
2561 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
2562 [317, [remove_extra_embedded_files]],
2563 [316, [revert_wrapplacement]],
2564 [315, [revert_subfig]],
2565 [314, [revert_colsep]],
2567 [312, [revert_module_names]],
2568 [311, [revert_rotfloat, revert_widesideways]],
2569 [310, [revert_external_embedding]],
2570 [309, [revert_btprintall]],
2571 [308, [revert_nocite]],
2572 [307, [revert_serbianlatin]],
2573 [306, [revert_slash, revert_nobreakdash]],
2574 [305, [revert_interlingua]],
2575 [304, [revert_bahasam]],
2576 [303, [revert_framed_notes]],
2578 [301, [revert_latin, revert_samin]],
2579 [300, [revert_linebreak]],
2580 [299, [revert_pagebreak]],
2581 [298, [revert_hyperlinktype]],
2582 [297, [revert_macro_optional_params]],
2583 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
2584 [295, [revert_include]],
2585 [294, [revert_href]],
2586 [293, [revert_pdf_options_2]],
2587 [292, [revert_inset_info]],
2588 [291, [revert_japanese, revert_japanese_encoding]],
2589 [290, [revert_vietnamese]],
2590 [289, [revert_wraptable]],
2591 [288, [revert_latexcommand_index]],
2592 [287, [revert_inset_command]],
2593 [286, [revert_wrapfig_options]],
2594 [285, [revert_pdf_options]],
2595 [284, [remove_inzip_options]],
2597 [282, [revert_flex]],
2599 [280, [revert_begin_modules]],
2600 [279, [revert_show_label]],
2601 [278, [revert_long_charstyle_names]],
2607 if __name__ == "__main__":