1 # This file is part of lyx2lyx
2 # Copyright (C) 2007-2008 The LyX Team <lyx-devel@lists.lyx.org>
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 """Convert files to the file format generated by lyx 1.6"""
24 from parser_tools import find_token, find_end_of, find_tokens, get_value
25 from unicode_symbols import unicode_reps
27 ####################################################################
28 # Private helper functions
31 def get_value_string(lines, token, start, end=0, trim=False, default=""):
32 """get_value_string(lines, token, start[[, end], trim, default]) -> string
34 Return tokens after token as string, in lines, where
35 token is the first element. When trim is used, the first and last character
36 of the string is trimmed."""
38 val = get_value(lines, token, start, end, "")
46 def find_end_of_inset(lines, i):
47 "Find end of inset, where lines[i] is included."
48 return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
53 # document.body[i] = wrap_insert_ert(...)
54 # wrap_into_ert may returns a multiline string, which should NOT appear
55 # in document.body. Instead, do something like this:
56 # subst = wrap_inset_ert(...)
57 # subst = subst.split('\n')
58 # document.body[i:i+1] = subst
60 # where the last statement resets the counter to accord with the added
62 def wrap_into_ert(string, src, dst):
63 """Within string, replace occurrences of src with dst, wrapped into ERT
64 E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is:
65 sch<ERT>\\backslash</ERT>"on"""
66 return string.replace(
68 "\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n"
70 + "\n\\end_layout\n\\end_inset\n",
74 def put_cmd_in_ert(string):
75 for rep in unicode_reps:
76 string = string.replace(rep[1], rep[0].replace("\\\\", "\\"))
77 string = string.replace("\\", "\\backslash\n")
79 "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n"
81 + "\n\\end_layout\n\\end_inset"
86 def add_to_preamble(document, text):
87 """Add text to the preamble if it is not already there.
88 Only the first line is checked!"""
90 if find_token(document.preamble, text[0], 0) != -1:
93 document.preamble.extend(text)
96 def insert_to_preamble(index, document, text):
97 """Insert text to the preamble at a given line"""
99 document.preamble.insert(index, text)
102 # Convert a LyX length into a LaTeX length
103 def convert_len(len):
105 "text%": "\\backslash\ntextwidth",
106 "col%": "\\backslash\ncolumnwidth",
107 "page%": "\\backslash\npagewidth",
108 "line%": "\\backslash\nlinewidth",
109 "theight%": "\\backslash\ntextheight",
110 "pheight%": "\\backslash\npageheight",
113 # Convert LyX units to LaTeX units
114 for unit in list(units.keys()):
115 if len.find(unit) != -1:
116 len = "%f" % (len2value(len) / 100)
117 len = len.strip("0") + units[unit]
123 # Return the value of len without the unit in numerical form.
125 result = re.search("([+-]?[0-9.]+)", len)
127 return float(result.group(1))
128 # No number means 1.0
132 # Unfortunately, this doesn't really work, since Standard isn't always default.
133 # But it's as good as we can do right now.
134 def find_default_layout(document, start, end):
135 l = find_token(document.body, "\\begin_layout Standard", start, end)
137 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
139 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
143 def get_option(document, m, option, default):
144 l = document.body[m].find(option)
147 val = document.body[m][l:].split('"')[1]
151 def remove_option(document, m, option):
152 l = document.body[m].find(option)
154 val = document.body[m][l:].split('"')[1]
156 document.body[m][: l - 1] + document.body[m][l + len(option + '="' + val + '"') :]
161 def set_option(document, m, option, value):
162 l = document.body[m].find(option)
164 oldval = document.body[m][l:].split('"')[1]
165 l = l + len(option + '="')
166 document.body[m] = document.body[m][:l] + value + document.body[m][l + len(oldval) :]
168 document.body[m] = document.body[m][:-1] + " " + option + '="' + value + '">'
172 def extract_argument(line):
173 "Extracts a LaTeX argument from the start of line. Returns (arg, rest)."
178 bracere = re.compile(r"(\s*)(.*)")
179 n = bracere.match(line)
180 whitespace = n.group(1)
183 if brace != "[" and brace != "{":
207 # We never found the matching brace
208 # So, to be on the safe side, let's just return everything
209 # which will then get wrapped as ERT
211 return (line[: pos + 1], line[pos + 1 :])
214 def latex2ert(line, isindex):
215 """Converts LaTeX commands into ERT. line may well be a multi-line
216 string when it is returned."""
221 ## FIXME Escaped \ ??
222 # This regex looks for a LaTeX command---i.e., something of the form
223 # "\alPhaStuFF", or "\X", where X is any character---where the command
224 # may also be preceded by an additional backslash, which is how it would
225 # appear (e.g.) in an InsetIndex.
226 labelre = re.compile(r"(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)")
228 m = labelre.match(line)
235 (arg, rest) = extract_argument(end)
240 # If we wanted to put labels into an InsetLabel, for example, then we
241 # would just need to test here for cmd == "label" and then take some
242 # appropriate action, i.e., to use arg to get the content and then
243 # wrap it appropriately.
244 cmd = put_cmd_in_ert(cmd)
245 retval += "\n" + cmd + "\n"
247 m = labelre.match(line)
248 # put all remaining braces in ERT
249 line = wrap_into_ert(line, "}", "}")
250 line = wrap_into_ert(line, "{", "{")
252 # active character that is not available in all font encodings
253 line = wrap_into_ert(line, "|", "|")
259 # Might should do latex2ert first, then deal with stuff that DOESN'T
260 # end up inside ERT. That routine could be modified so that it returned
261 # a list of lines, and we could then skip ERT bits and only deal with
263 def latex2lyx(data, isindex):
264 """Takes a string, possibly multi-line, and returns the result of
265 converting LaTeX constructs into LyX constructs. Returns a list of
266 lines, suitable for insertion into document.body.
267 The bool isindex specifies whether we are in an index macro (which
268 has some specific active characters that need to be ERTed)."""
274 # Convert LaTeX to Unicode
275 # Commands of this sort need to be checked to make sure they are
276 # followed by a non-alpha character, lest we replace too much.
277 hardone = re.compile(r"^\\\\[a-zA-Z]+$")
279 for rep in unicode_reps:
280 if hardone.match(rep[0]):
283 pos = data.find(rep[0], pos)
286 nextpos = pos + len(rep[0])
287 if nextpos < len(data) and data[nextpos].isalpha():
288 # not the end of that command
291 data = data[:pos] + rep[1] + data[nextpos:]
294 data = data.replace(rep[0], rep[1])
298 data = wrap_into_ert(data, r"\"", '"')
300 data = data.replace("\\\\", "\\")
303 mathre = re.compile(r"^(.*?)(\$.*?\$)(.*)")
304 lines = data.split("\n")
306 # document.warning("LINE: " + line)
307 # document.warning(str(i) + ":" + document.body[i])
308 # document.warning("LAST: " + document.body[-1])
313 f = m.group(2).replace("\\\\", "\\")
317 s = latex2ert(s, isindex)
318 subst = s.split("\n")
320 retval.append("\\begin_inset Formula " + f)
321 retval.append("\\end_inset")
323 # Handle whatever is left, which is just text
324 g = latex2ert(g, isindex)
325 subst = g.split("\n")
330 def lyxline2latex(document, line, inert):
331 "Convert some LyX stuff into corresponding LaTeX stuff line-wise, as best we can."
332 if line.startswith("\\begin_inset Formula"):
334 elif line.startswith("\\begin_inset Quotes"):
335 # For now, we do a very basic reversion. Someone who understands
336 # quotes is welcome to fix it up.
337 qtype = line[20:].strip()
353 or line.startswith("\\begin_layout")
354 or line.startswith("\\end_layout")
355 or line.startswith("\\begin_inset")
356 or line.startswith("\\end_inset")
357 or line.startswith("\\lang")
358 or line.strip() == "status collapsed"
359 or line.strip() == "status open"
361 # skip all that stuff
364 # this needs to be added to the preamble because of cases like
365 # \textmu, \textbackslash, etc.
369 "% added by lyx2lyx for converted entries",
370 "\\@ifundefined{textmu}",
371 " {\\usepackage{textcomp}}{}",
374 # a lossless reversion is not possible
375 # try at least to handle some common insets and settings
377 line = line.replace(r"\backslash", "\\")
379 line = line.replace("&", "\\&{}")
380 line = line.replace("#", "\\#{}")
381 line = line.replace("^", "\\^{}")
382 line = line.replace("%", "\\%{}")
383 line = line.replace("_", "\\_{}")
384 line = line.replace("$", "\\${}")
386 # Do the LyX text --> LaTeX conversion
387 for rep in unicode_reps:
388 line = line.replace(rep[1], rep[0].replace("\\\\", "\\") + "{}")
389 line = line.replace(r"\backslash", r"\textbackslash{}")
390 line = line.replace(r"\series bold", r"\bfseries{}").replace(
391 r"\series default", r"\mdseries{}"
393 line = line.replace(r"\shape italic", r"\itshape{}").replace(
394 r"\shape smallcaps", r"\scshape{}"
396 line = line.replace(r"\shape slanted", r"\slshape{}").replace(
397 r"\shape default", r"\upshape{}"
399 line = line.replace(r"\emph on", r"\em{}").replace(r"\emph default", r"\em{}")
400 line = line.replace(r"\noun on", r"\scshape{}").replace(
401 r"\noun default", r"\upshape{}"
403 line = line.replace(r"\bar under", r"\underbar{").replace(r"\bar default", r"}")
404 line = line.replace(r"\family sans", r"\sffamily{}").replace(
405 r"\family default", r"\normalfont{}"
407 line = line.replace(r"\family typewriter", r"\ttfamily{}").replace(
408 r"\family roman", r"\rmfamily{}"
410 line = line.replace(r"\InsetSpace ", r"").replace(r"\SpecialChar ", r"")
414 def lyx2latex(document, lines):
415 "Convert some LyX stuff into corresponding LaTeX stuff, as best we can."
416 # clean up multiline stuff
420 for curline in range(len(lines)):
421 line = lines[curline]
422 if line.startswith("\\begin_inset ERT"):
423 # We don't want to replace things inside ERT, so figure out
424 # where the end of the inset is.
425 ert_end = find_end_of_inset(lines, curline + 1)
427 inert = ert_end >= curline
428 content += lyxline2latex(document, lines[curline], inert)
433 ####################################################################
436 def convert_ltcaption(document):
439 i = find_token(document.body, "\\begin_inset Tabular", i)
442 j = find_end_of_inset(document.body, i + 1)
444 document.warning("Malformed LyX document: Could not find end of tabular.")
448 nrows = int(document.body[i + 1].split('"')[3])
449 ncols = int(document.body[i + 1].split('"')[5])
452 for k in range(nrows):
453 m = find_token(document.body, "<row", m)
456 for k in range(ncols):
457 m = find_token(document.body, "<cell", m)
459 mend = find_token(document.body, "</cell>", m + 1)
460 # first look for caption insets
461 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
462 # then look for ERT captions
464 mcap = find_token(document.body, "caption", m + 1, mend)
466 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
469 if caption == "true":
471 set_option(document, r, "caption", "true")
472 set_option(document, m, "multicolumn", "1")
473 set_option(document, m, "bottomline", "false")
474 set_option(document, m, "topline", "false")
475 set_option(document, m, "rightline", "false")
476 set_option(document, m, "leftline", "false")
477 # j = find_end_of_inset(document.body, j + 1)
479 set_option(document, m, "multicolumn", "2")
486 # FIXME Use of wrap_into_ert can confuse lyx2lyx
487 def revert_ltcaption(document):
490 i = find_token(document.body, "\\begin_inset Tabular", i)
493 j = find_end_of_inset(document.body, i + 1)
495 document.warning("Malformed LyX document: Could not find end of tabular.")
500 nrows = int(document.body[i + 1].split('"')[3])
501 ncols = int(document.body[i + 1].split('"')[5])
503 for k in range(nrows):
504 m = find_token(document.body, "<row", m)
505 caption = get_option(document, m, "caption", "false")
506 if caption == "true":
507 remove_option(document, m, "caption")
508 for k in range(ncols):
509 m = find_token(document.body, "<cell", m)
510 remove_option(document, m, "multicolumn")
512 m = find_token(document.body, "\\begin_inset Caption", m)
515 m = find_end_of_inset(document.body, m + 1)
516 document.body[m] += wrap_into_ert("", "", "\\backslash\n\\backslash\n%")
522 def convert_tablines(document):
525 i = find_token(document.body, "\\begin_inset Tabular", i)
527 # LyX 1.3 inserted an extra space between \begin_inset
528 # and Tabular so let us try if this is the case and fix it.
529 i = find_token(document.body, "\\begin_inset Tabular", i)
533 document.body[i] = "\\begin_inset Tabular"
534 j = find_end_of_inset(document.body, i + 1)
536 document.warning("Malformed LyX document: Could not find end of tabular.")
541 nrows = int(document.body[i + 1].split('"')[3])
542 ncols = int(document.body[i + 1].split('"')[5])
545 for k in range(ncols):
546 m = find_token(document.body, "<column", m)
547 left = get_option(document, m, "leftline", "false")
548 right = get_option(document, m, "rightline", "false")
549 col_info.append([left, right])
550 remove_option(document, m, "leftline")
551 remove_option(document, m, "rightline")
555 for k in range(nrows):
556 m = find_token(document.body, "<row", m)
557 top = get_option(document, m, "topline", "false")
558 bottom = get_option(document, m, "bottomline", "false")
559 row_info.append([top, bottom])
560 remove_option(document, m, "topline")
561 remove_option(document, m, "bottomline")
566 for k in range(nrows * ncols):
567 m = find_token(document.body, "<cell", m)
568 mc_info.append(get_option(document, m, "multicolumn", "0"))
571 for l in range(nrows):
572 for k in range(ncols):
573 m = find_token(document.body, "<cell", m)
574 if mc_info[l * ncols + k] == "0":
575 r = set_option(document, m, "topline", row_info[l][0])
576 r = set_option(document, m, "bottomline", row_info[l][1])
577 r = set_option(document, m, "leftline", col_info[k][0])
578 r = set_option(document, m, "rightline", col_info[k][1])
579 elif mc_info[l * ncols + k] == "1":
581 while s < ncols and mc_info[l * ncols + s] == "2":
583 if s < ncols and mc_info[l * ncols + s] != "1":
584 r = set_option(document, m, "rightline", col_info[k][1])
585 if k > 0 and mc_info[l * ncols + k - 1] == "0":
586 r = set_option(document, m, "leftline", col_info[k][0])
591 def revert_tablines(document):
594 i = find_token(document.body, "\\begin_inset Tabular", i)
597 j = find_end_of_inset(document.body, i)
599 document.warning("Malformed LyX document: Could not find end of tabular.")
604 nrows = int(document.body[i + 1].split('"')[3])
605 ncols = int(document.body[i + 1].split('"')[5])
608 for k in range(nrows * ncols):
609 m = find_token(document.body, "<cell", m)
610 top = get_option(document, m, "topline", "false")
611 bottom = get_option(document, m, "bottomline", "false")
612 left = get_option(document, m, "leftline", "false")
613 right = get_option(document, m, "rightline", "false")
614 lines.append([top, bottom, left, right])
617 # we will want to ignore longtable captions
620 for k in range(nrows):
621 m = find_token(document.body, "<row", m)
622 caption = get_option(document, m, "caption", "false")
623 caption_info.append([caption])
628 for k in range(ncols):
629 m = find_token(document.body, "<column", m)
631 for l in range(nrows):
632 left = lines[l * ncols + k][2]
633 if left == "false" and caption_info[l] == "false":
635 set_option(document, m, "leftline", left)
637 for l in range(nrows):
638 right = lines[l * ncols + k][3]
639 if right == "false" and caption_info[l] == "false":
641 set_option(document, m, "rightline", right)
645 for k in range(nrows):
646 m = find_token(document.body, "<row", m)
648 for l in range(ncols):
649 top = lines[k * ncols + l][0]
652 if caption_info[k] == "false":
654 set_option(document, m, "topline", top)
656 for l in range(ncols):
657 bottom = lines[k * ncols + l][1]
658 if bottom == "false":
660 if caption_info[k] == "false":
662 set_option(document, m, "bottomline", bottom)
668 def fix_wrong_tables(document):
671 i = find_token(document.body, "\\begin_inset Tabular", i)
674 j = find_end_of_inset(document.body, i + 1)
676 document.warning("Malformed LyX document: Could not find end of tabular.")
681 nrows = int(document.body[i + 1].split('"')[3])
682 ncols = int(document.body[i + 1].split('"')[5])
684 for l in range(nrows):
686 for k in range(ncols):
687 m = find_token(document.body, "<cell", m)
689 if document.body[m].find("multicolumn") != -1:
690 multicol_cont = int(document.body[m].split('"')[1])
692 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
693 document.body[m] = document.body[m][:5] + document.body[m][21:]
696 prev_multicolumn = multicol_cont
703 def close_begin_deeper(document):
707 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
712 if document.body[i][:13] == "\\begin_deeper":
719 document.body[-2:-2] = ["\\end_deeper" for i in range(depth)]
722 def long_charstyle_names(document):
725 i = find_token(document.body, "\\begin_inset CharStyle", i)
728 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
732 def revert_long_charstyle_names(document):
735 i = find_token(document.body, "\\begin_inset CharStyle", i)
738 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
742 def axe_show_label(document):
745 i = find_token(document.body, "\\begin_inset CharStyle", i)
748 if document.body[i + 1].find("show_label") != -1:
749 if document.body[i + 1].find("true") != -1:
750 document.body[i + 1] = "status open"
751 del document.body[i + 2]
753 if document.body[i + 1].find("false") != -1:
754 document.body[i + 1] = "status collapsed"
755 del document.body[i + 2]
758 "Malformed LyX document: show_label neither false nor true."
761 document.warning("Malformed LyX document: show_label missing in CharStyle.")
766 def revert_show_label(document):
769 i = find_token(document.body, "\\begin_inset CharStyle", i)
772 if document.body[i + 1].find("status open") != -1:
773 document.body.insert(i + 1, "show_label true")
775 if document.body[i + 1].find("status collapsed") != -1:
776 document.body.insert(i + 1, "show_label false")
778 document.warning("Malformed LyX document: no legal status line in CharStyle.")
782 def revert_begin_modules(document):
785 i = find_token(document.header, "\\begin_modules", i)
788 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
790 # this should not happen
792 document.header[i : j + 1] = []
795 def convert_flex(document):
796 "Convert CharStyle to Flex"
799 i = find_token(document.body, "\\begin_inset CharStyle", i)
802 document.body[i] = document.body[i].replace(
803 "\\begin_inset CharStyle", "\\begin_inset Flex"
807 def revert_flex(document):
808 "Revert Flex to CharStyle"
811 i = find_token(document.body, "\\begin_inset Flex", i)
814 document.body[i] = document.body[i].replace(
815 "\\begin_inset Flex", "\\begin_inset CharStyle"
819 def revert_pdf_options(document):
820 "Revert PDF options for hyperref."
821 # store the PDF options and delete the entries from the Lyx file
829 bookmarksnumbered = ""
831 bookmarksopenlevel = ""
839 i = find_token(document.header, "\\use_hyperref", i)
841 hyperref = get_value(document.header, "\\use_hyperref", i) == "true"
842 del document.header[i]
843 i = find_token(document.header, "\\pdf_store_options", i)
845 del document.header[i]
846 i = find_token(document.header, "\\pdf_title", 0)
848 title = get_value_string(document.header, "\\pdf_title", 0, 0, True)
849 title = " pdftitle={" + title + "}"
850 del document.header[i]
851 i = find_token(document.header, "\\pdf_author", 0)
853 author = get_value_string(document.header, "\\pdf_author", 0, 0, True)
855 author = " pdfauthor={" + author + "}"
857 author = ",\n pdfauthor={" + author + "}"
858 del document.header[i]
859 i = find_token(document.header, "\\pdf_subject", 0)
861 subject = get_value_string(document.header, "\\pdf_subject", 0, 0, True)
862 if title == "" and author == "":
863 subject = " pdfsubject={" + subject + "}"
865 subject = ",\n pdfsubject={" + subject + "}"
866 del document.header[i]
867 i = find_token(document.header, "\\pdf_keywords", 0)
869 keywords = get_value_string(document.header, "\\pdf_keywords", 0, 0, True)
870 if title == "" and author == "" and subject == "":
871 keywords = " pdfkeywords={" + keywords + "}"
873 keywords = ",\n pdfkeywords={" + keywords + "}"
874 del document.header[i]
875 i = find_token(document.header, "\\pdf_bookmarks", 0)
877 bookmarks = get_value_string(document.header, "\\pdf_bookmarks", 0)
878 bookmarks = ",\n bookmarks=" + bookmarks
879 del document.header[i]
880 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
882 bookmarksnumbered = get_value_string(document.header, "\\pdf_bookmarksnumbered", 0)
883 bookmarksnumbered = ",\n bookmarksnumbered=" + bookmarksnumbered
884 del document.header[i]
885 i = find_token(document.header, "\\pdf_bookmarksopen", i)
887 bookmarksopen = get_value_string(document.header, "\\pdf_bookmarksopen", 0)
888 bookmarksopen = ",\n bookmarksopen=" + bookmarksopen
889 del document.header[i]
890 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
892 bookmarksopenlevel = get_value_string(
893 document.header, "\\pdf_bookmarksopenlevel", 0, 0, True
895 bookmarksopenlevel = ",\n bookmarksopenlevel=" + bookmarksopenlevel
896 del document.header[i]
897 i = find_token(document.header, "\\pdf_breaklinks", i)
899 breaklinks = get_value_string(document.header, "\\pdf_breaklinks", 0)
900 breaklinks = ",\n breaklinks=" + breaklinks
901 del document.header[i]
902 i = find_token(document.header, "\\pdf_pdfborder", i)
904 pdfborder = get_value_string(document.header, "\\pdf_pdfborder", 0)
905 if pdfborder == "true":
906 pdfborder = ",\n pdfborder={0 0 0}"
908 pdfborder = ",\n pdfborder={0 0 1}"
909 del document.header[i]
910 i = find_token(document.header, "\\pdf_colorlinks", i)
912 colorlinks = get_value_string(document.header, "\\pdf_colorlinks", 0)
913 colorlinks = ",\n colorlinks=" + colorlinks
914 del document.header[i]
915 i = find_token(document.header, "\\pdf_backref", i)
917 backref = get_value_string(document.header, "\\pdf_backref", 0)
918 backref = ",\n backref=" + backref
919 del document.header[i]
920 i = find_token(document.header, "\\pdf_pagebackref", i)
922 pagebackref = get_value_string(document.header, "\\pdf_pagebackref", 0)
923 pagebackref = ",\n pagebackref=" + pagebackref
924 del document.header[i]
925 i = find_token(document.header, "\\pdf_pagemode", 0)
927 pagemode = get_value_string(document.header, "\\pdf_pagemode", 0)
928 pagemode = ",\n pdfpagemode=" + pagemode
929 del document.header[i]
930 i = find_token(document.header, "\\pdf_quoted_options", 0)
932 otheroptions = get_value_string(document.header, "\\pdf_quoted_options", 0, 0, True)
933 if title == "" and author == "" and subject == "" and keywords == "":
934 otheroptions = " " + otheroptions
936 otheroptions = ",\n " + otheroptions
937 del document.header[i]
939 # write to the preamble when hyperref was used
941 # preamble write preparations
942 # bookmark numbers are only output when they are turned on
943 if bookmarksopen == ",\n bookmarksopen=true":
944 bookmarksopen = bookmarksopen + bookmarksopenlevel
945 if bookmarks == ",\n bookmarks=true":
946 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
948 bookmarks = bookmarks
949 # hypersetup is only output when there are things to be set up
950 setupstart = "\\hypersetup{%\n"
962 # babel must be loaded before hyperref and hyperref the first part
963 # of the preamble, like in LyX 1.6
967 "% Commands inserted by lyx2lyx for PDF properties\n"
968 + "\\usepackage{babel}\n"
969 + "\\usepackage[unicode=true"
989 def remove_inzip_options(document):
990 "Remove inzipName and embed options from the Graphics inset"
993 i = find_token(document.body, "\\begin_inset Graphics", i)
996 j = find_end_of_inset(document.body, i + 1)
999 document.warning("Malformed LyX document: Could not find end of graphics inset.")
1002 # If there's a inzip param, just remove that
1003 k = find_token(document.body, "\tinzipName", i + 1, j)
1005 del document.body[k]
1006 # embed option must follow the inzipName option
1007 del document.body[k + 1]
1011 def convert_inset_command(document):
1014 \begin_inset LatexCommand cmd
1016 \begin_inset CommandInset InsetType
1021 i = find_token(document.body, "\\begin_inset LatexCommand", i)
1024 line = document.body[i]
1025 r = re.compile(r"\\begin_inset LatexCommand (.*)$")
1027 cmdName = m.group(1)
1029 # this is adapted from factory.cpp
1030 if cmdName[0:4].lower() == "cite":
1031 insetName = "citation"
1032 elif cmdName == "url" or cmdName == "htmlurl":
1034 elif cmdName[-3:] == "ref":
1036 elif cmdName == "tableofcontents":
1038 elif cmdName == "printnomenclature":
1039 insetName = "nomencl_print"
1040 elif cmdName == "printindex":
1041 insetName = "index_print"
1045 "\\begin_inset CommandInset " + insetName,
1046 "LatexCommand " + cmdName,
1048 document.body[i : i + 1] = insertion
1051 def revert_inset_command(document):
1054 \begin_inset CommandInset InsetType
1057 \begin_inset LatexCommand cmd
1058 Some insets may end up being converted to insets earlier versions of LyX
1059 will not be able to recognize. Not sure what to do about that.
1063 i = find_token(document.body, "\\begin_inset CommandInset", i)
1066 nextline = document.body[i + 1]
1067 r = re.compile(r"LatexCommand\s+(.*)$")
1068 m = r.match(nextline)
1071 "Malformed LyX document: Missing LatexCommand in " + document.body[i] + "."
1075 cmdName = m.group(1)
1076 insertion = ["\\begin_inset LatexCommand " + cmdName]
1077 document.body[i : i + 2] = insertion
1080 def convert_wrapfig_options(document):
1081 "Convert optional options for wrap floats (wrapfig)."
1082 # adds the tokens "lines", "placement", and "overhang"
1085 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1088 document.body.insert(i + 1, "lines 0")
1089 j = find_token(document.body, "placement", i)
1090 # placement can be already set or not; if not, set it
1092 document.body.insert(i + 3, "overhang 0col%")
1094 document.body.insert(i + 2, "placement o")
1095 document.body.insert(i + 3, "overhang 0col%")
1099 def revert_wrapfig_options(document):
1100 "Revert optional options for wrap floats (wrapfig)."
1103 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1106 j = find_end_of_inset(document.body, i)
1108 document.warning("Can't find end of Wrap inset at line " + str(i))
1111 k = find_default_layout(document, i, j)
1113 document.warning("Can't find default layout for Wrap figure!")
1116 # Options should be between i and k now
1117 l = find_token(document.body, "lines", i, k)
1119 document.warning("Can't find lines option for Wrap figure!")
1122 m = find_token(document.body, "overhang", i + 1, k)
1125 "Malformed LyX document: Couldn't find overhang parameter of wrap float!"
1129 # Do these in reverse order
1130 del document.body[m]
1131 del document.body[l]
1135 def convert_latexcommand_index(document):
1136 "Convert from LatexCommand form to collapsible form."
1138 r1 = re.compile('name "(.*)"')
1140 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1143 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1146 j = find_end_of_inset(document.body, i + 1)
1148 document.warning("Unable to find end of index inset at line " + str(i) + "!")
1151 m = r1.match(document.body[i + 2])
1153 document.warning("Unable to match: " + document.body[i + 2])
1154 # this can happen with empty index insets!
1157 fullcontent = m.group(1)
1158 linelist = latex2lyx(fullcontent, True)
1159 # document.warning(fullcontent)
1162 ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""]
1166 document.body[i:j] = linelist
1167 i += len(linelist) - (j - i)
1170 def revert_latexcommand_index(document):
1171 "Revert from collapsible form to LatexCommand form."
1174 i = find_token(document.body, "\\begin_inset Index", i)
1177 j = find_end_of_inset(document.body, i + 1)
1181 content = lyx2latex(document, document.body[i:j])
1183 content = content.replace('"', r"\"")
1184 document.body[i:j] = [
1185 "\\begin_inset CommandInset index",
1186 "LatexCommand index",
1187 "name " + '"' + content + '"',
1193 def revert_wraptable(document):
1194 "Revert wrap table to wrap figure."
1197 i = find_token(document.body, "\\begin_inset Wrap table", i)
1200 document.body[i] = document.body[i].replace(
1201 "\\begin_inset Wrap table", "\\begin_inset Wrap figure"
1206 def revert_vietnamese(document):
1207 "Set language Vietnamese to English"
1208 # Set document language from Vietnamese to English
1210 if document.language == "vietnamese":
1211 document.language = "english"
1212 i = find_token(document.header, "\\language", 0)
1214 document.header[i] = "\\language english"
1217 j = find_token(document.body, "\\lang vietnamese", j)
1220 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1224 def convert_japanese_cjk(document):
1225 "Set language japanese to japanese-cjk"
1226 # Set document language from japanese-plain to japanese
1228 if document.language == "japanese":
1229 document.language = "japanese-cjk"
1230 i = find_token(document.header, "\\language", 0)
1232 document.header[i] = "\\language japanese-cjk"
1235 j = find_token(document.body, "\\lang japanese", j)
1238 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1242 def revert_japanese(document):
1243 "Set language japanese-plain to japanese"
1244 # Set document language from japanese-plain to japanese
1246 if document.language == "japanese-plain":
1247 document.language = "japanese"
1248 i = find_token(document.header, "\\language", 0)
1250 document.header[i] = "\\language japanese"
1253 j = find_token(document.body, "\\lang japanese-plain", j)
1256 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1260 def revert_japanese_cjk(document):
1261 "Set language japanese-cjk to japanese"
1262 # Set document language from japanese-plain to japanese
1264 if document.language == "japanese-cjk":
1265 document.language = "japanese"
1266 i = find_token(document.header, "\\language", 0)
1268 document.header[i] = "\\language japanese"
1271 j = find_token(document.body, "\\lang japanese-cjk", j)
1274 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1278 def revert_japanese_encoding(document):
1279 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1280 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1282 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1284 document.header[i] = "\\inputencoding EUC-JP"
1286 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1288 document.header[j] = "\\inputencoding JIS"
1290 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1291 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1292 document.header[k] = "\\inputencoding UTF8"
1295 def revert_inset_info(document):
1296 "Replace info inset with its content"
1299 i = find_token(document.body, "\\begin_inset Info", i)
1302 j = find_end_of_inset(document.body, i + 1)
1305 document.warning("Malformed LyX document: Could not find end of Info inset.")
1310 for k in range(i, j + 1):
1311 if document.body[k].startswith("arg"):
1312 arg = document.body[k][3:].strip()
1313 # remove embracing quotation marks
1316 if arg[len(arg) - 1] == '"':
1317 arg = arg[: len(arg) - 1]
1318 # \" to straight quote
1319 arg = arg.replace(r"\"", '"')
1321 arg = arg.replace(r"\\", "\\backslash\n")
1322 if document.body[k].startswith("type"):
1323 type = document.body[k][4:].strip().strip('"')
1324 # I think there is a newline after \\end_inset, which should be removed.
1325 if document.body[j + 1].strip() == "":
1326 document.body[i : (j + 2)] = [type + ":" + arg]
1328 document.body[i : (j + 1)] = [type + ":" + arg]
1331 def convert_pdf_options(document):
1332 # Set the pdfusetitle tag, delete the pdf_store_options,
1333 # set quotes for bookmarksopenlevel"
1334 has_hr = get_value(document.header, "\\use_hyperref", 0, default="0")
1336 k = find_token(document.header, "\\use_hyperref", 0)
1337 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1338 k = find_token(document.header, "\\pdf_store_options", 0)
1340 del document.header[k]
1341 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1344 document.header[i] = document.header[i].replace('"', "")
1347 def revert_pdf_options_2(document):
1348 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1349 k = find_token(document.header, "\\use_hyperref", 0)
1350 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1352 del document.header[i]
1353 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1356 values = document.header[i].split()
1357 values[1] = ' "' + values[1] + '"'
1358 document.header[i] = "".join(values)
1361 def convert_htmlurl(document):
1362 'Convert "htmlurl" to "href" insets for docbook'
1363 if document.backend != "docbook":
1367 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1370 document.body[i] = "\\begin_inset CommandInset href"
1371 document.body[i + 1] = "LatexCommand href"
1375 def convert_url(document):
1376 "Convert url insets to url charstyles"
1377 if document.backend == "docbook":
1381 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1384 n = find_token(document.body, "name", i)
1386 # place the URL name in typewriter before the new URL insert
1387 # grab the name 'bla' from the e.g. the line 'name "bla"',
1388 # therefore start with the 6th character
1389 name = document.body[n][6:-1]
1390 newname = [name + " "]
1391 document.body[i:i] = newname
1393 j = find_token(document.body, "target", i)
1395 document.warning("Malformed LyX document: Can't find target for url inset")
1398 target = document.body[j][8:-1]
1399 k = find_token(document.body, "\\end_inset", j)
1401 document.warning("Malformed LyX document: Can't find end of url inset")
1405 "\\begin_inset Flex URL",
1408 "\\begin_layout Standard",
1414 document.body[i:k] = newstuff
1415 i = i + len(newstuff)
1418 def convert_ams_classes(document):
1419 tc = document.textclass
1420 if tc != "amsart" and tc != "amsart-plain" and tc != "amsart-seq" and tc != "amsbook":
1422 if tc == "amsart-plain":
1423 document.textclass = "amsart"
1424 document.set_textclass()
1425 document.add_module("Theorems (Starred)")
1427 if tc == "amsart-seq":
1428 document.textclass = "amsart"
1429 document.set_textclass()
1430 document.add_module("Theorems (AMS)")
1432 # Now we want to see if any of the environments in the extended theorems
1433 # module were used in this document. If so, we'll add that module, too.
1448 r = re.compile(r"^\\begin_layout (.*?)\*?\s*$")
1451 i = find_token(document.body, "\\begin_layout", i)
1454 m = r.match(document.body[i])
1456 # This is an empty layout
1457 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1461 if layouts.count(m) != 0:
1462 document.add_module("Theorems (AMS-Extended)")
1467 def revert_href(document):
1468 "Reverts hyperlink insets (href) to url insets (url)"
1471 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1474 document.body[i : i + 2] = [
1475 "\\begin_inset CommandInset url",
1481 def revert_url(document):
1482 "Reverts Flex URL insets to old-style URL insets"
1485 i = find_token(document.body, "\\begin_inset Flex URL", i)
1488 j = find_end_of_inset(document.body, i)
1490 document.warning("Can't find end of inset in revert_url!")
1492 k = find_default_layout(document, i, j)
1494 document.warning("Can't find default layout in revert_url!")
1497 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1498 if l == -1 or l >= j:
1499 document.warning("Can't find end of default layout in revert_url!")
1502 # OK, so the inset's data is between lines k and l.
1503 data = " ".join(document.body[k + 1 : l])
1506 "\\begin_inset LatexCommand url",
1507 'target "' + data + '"',
1511 document.body[i : j + 1] = newinset
1512 i = i + len(newinset)
1515 def convert_include(document):
1516 "Converts include insets to new format."
1518 r = re.compile(r"\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?")
1520 i = find_token(document.body, "\\begin_inset Include", i)
1523 line = document.body[i]
1524 previewline = document.body[i + 1]
1527 document.warning("Unable to match line " + str(i) + " of body!")
1534 "\\begin_inset CommandInset include",
1535 "LatexCommand " + cmd,
1537 'filename "' + fn + '"',
1541 insertion.append("lstparams " + '"' + opt + '"')
1543 document.body[i : i + 2] = insertion
1547 def revert_include(document):
1548 "Reverts include insets to old format."
1550 r0 = re.compile("preview.*")
1551 r1 = re.compile("LatexCommand (.+)")
1552 r2 = re.compile('filename "(.+)"')
1553 r3 = re.compile('lstparams "(.*)"')
1555 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1559 m = r1.match(document.body[nextline])
1562 "Malformed LyX document: No LatexCommand line for `"
1572 if r0.match(document.body[nextline]):
1573 previewline = document.body[nextline]
1577 m = r2.match(document.body[nextline])
1580 "Malformed LyX document: No filename line for `"
1591 if cmd == "lstinputlisting":
1592 m = r3.match(document.body[nextline])
1594 options = m.group(1)
1597 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1599 newline += "[" + options + "]"
1600 insertion = [newline]
1601 if previewline != "":
1602 insertion.append(previewline)
1603 document.body[i:nextline] = insertion
1607 def revert_albanian(document):
1608 "Set language Albanian to English"
1610 if document.language == "albanian":
1611 document.language = "english"
1612 i = find_token(document.header, "\\language", 0)
1614 document.header[i] = "\\language english"
1617 j = find_token(document.body, "\\lang albanian", j)
1620 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1624 def revert_lowersorbian(document):
1625 "Set language lower Sorbian to English"
1627 if document.language == "lowersorbian":
1628 document.language = "english"
1629 i = find_token(document.header, "\\language", 0)
1631 document.header[i] = "\\language english"
1634 j = find_token(document.body, "\\lang lowersorbian", j)
1637 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1641 def revert_uppersorbian(document):
1642 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1644 if document.language == "uppersorbian":
1645 document.language = "usorbian"
1646 i = find_token(document.header, "\\language", 0)
1648 document.header[i] = "\\language usorbian"
1651 j = find_token(document.body, "\\lang uppersorbian", j)
1654 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1658 def convert_usorbian(document):
1659 "Set language usorbian to uppersorbian"
1661 if document.language == "usorbian":
1662 document.language = "uppersorbian"
1663 i = find_token(document.header, "\\language", 0)
1665 document.header[i] = "\\language uppersorbian"
1668 j = find_token(document.body, "\\lang usorbian", j)
1671 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1675 def convert_macro_global(document):
1676 r"Remove TeX code command \global when it is in front of a macro"
1677 # math macros are nowadays already defined \global, so that an additional
1678 # \global would make the document uncompilable, see
1679 # http://www.lyx.org/trac/ticket/5371
1680 # We're looking for something like this:
1684 # \begin_layout Plain Layout
1694 # \begin_inset FormulaMacro
1695 # \renewcommand{\foo}{123}
1699 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1702 # if i <= 13, then there isn't enough room for the ERT
1706 if document.body[i - 6] == "global":
1707 del document.body[i - 13 : i]
1713 def revert_macro_optional_params(document):
1714 "Convert macro definitions with optional parameters into ERTs"
1715 # Stub to convert macro definitions with one or more optional parameters
1716 # into uninterpreted ERT insets
1719 def revert_hyperlinktype(document):
1720 "Reverts hyperlink type"
1724 i = find_token(document.body, "target", i)
1727 j = find_token(document.body, "type", i)
1731 del document.body[j]
1735 def revert_pagebreak(document):
1736 "Reverts pagebreak to ERT"
1739 i = find_token(document.body, "\\pagebreak", i)
1742 document.body[i] = (
1743 "\\begin_inset ERT\nstatus collapsed\n\n"
1744 "\\begin_layout Standard\n\n\n\\backslash\n"
1745 "pagebreak{}\n\\end_layout\n\n\\end_inset\n\n"
1750 def revert_linebreak(document):
1751 "Reverts linebreak to ERT"
1754 i = find_token(document.body, "\\linebreak", i)
1757 document.body[i] = (
1758 "\\begin_inset ERT\nstatus collapsed\n\n"
1759 "\\begin_layout Standard\n\n\n\\backslash\n"
1760 "linebreak{}\n\\end_layout\n\n\\end_inset\n\n"
1765 def revert_latin(document):
1766 "Set language Latin to English"
1768 if document.language == "latin":
1769 document.language = "english"
1770 i = find_token(document.header, "\\language", 0)
1772 document.header[i] = "\\language english"
1775 j = find_token(document.body, "\\lang latin", j)
1778 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1782 def revert_samin(document):
1783 "Set language North Sami to English"
1785 if document.language == "samin":
1786 document.language = "english"
1787 i = find_token(document.header, "\\language", 0)
1789 document.header[i] = "\\language english"
1792 j = find_token(document.body, "\\lang samin", j)
1795 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1799 def convert_serbocroatian(document):
1800 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1802 if document.language == "serbocroatian":
1803 document.language = "croatian"
1804 i = find_token(document.header, "\\language", 0)
1806 document.header[i] = "\\language croatian"
1809 j = find_token(document.body, "\\lang serbocroatian", j)
1812 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1816 def convert_framed_notes(document):
1817 "Convert framed notes to boxes."
1821 document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i
1826 document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1835 'height_special "totalheight"',
1837 document.body[i : i + 1] = subst
1841 def convert_module_names(document):
1843 "Braille": "braille",
1844 "Endnote": "endnotes",
1845 "Foot to End": "foottoend",
1846 "Hanging": "hanging",
1847 "Linguistics": "linguistics",
1848 "Logical Markup": "logicalmkup",
1849 "Theorems (AMS-Extended)": "theorems-ams-extended",
1850 "Theorems (AMS)": "theorems-ams",
1851 "Theorems (Order By Chapter)": "theorems-chap",
1852 "Theorems (Order By Section)": "theorems-sec",
1853 "Theorems (Starred)": "theorems-starred",
1854 "Theorems": "theorems-std",
1856 modlist = document.get_module_list()
1857 if len(modlist) == 0:
1861 if mod in modulemap:
1862 newmodlist.append(modulemap[mod])
1864 document.warning("Can't find module %s in the module map!" % mod)
1865 newmodlist.append(mod)
1866 document.set_module_list(newmodlist)
1869 def revert_module_names(document):
1871 "braille": "Braille",
1872 "endnotes": "Endnote",
1873 "foottoend": "Foot to End",
1874 "hanging": "Hanging",
1875 "linguistics": "Linguistics",
1876 "logicalmkup": "Logical Markup",
1877 "theorems-ams-extended": "Theorems (AMS-Extended)",
1878 "theorems-ams": "Theorems (AMS)",
1879 "theorems-chap": "Theorems (Order By Chapter)",
1880 "theorems-sec": "Theorems (Order By Section)",
1881 "theorems-starred": "Theorems (Starred)",
1882 "theorems-std": "Theorems",
1884 modlist = document.get_module_list()
1885 if len(modlist) == 0:
1889 if mod in modulemap:
1890 newmodlist.append(modulemap[mod])
1892 document.warning("Can't find module %s in the module map!" % mod)
1893 newmodlist.append(mod)
1894 document.set_module_list(newmodlist)
1897 def revert_colsep(document):
1898 i = find_token(document.header, "\\columnsep", 0)
1901 colsepline = document.header[i]
1902 r = re.compile(r"\\columnsep (.*)")
1903 m = r.match(colsepline)
1905 document.warning("Malformed column separation line!")
1908 del document.header[i]
1909 # it seems to be safe to add the package even if it is already used
1910 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1912 add_to_preamble(document, pretext)
1915 def revert_framed_notes(document):
1916 "Revert framed boxes to notes."
1920 document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i
1925 j = find_end_of_inset(document.body, i + 1)
1928 document.warning("Malformed LyX document: Could not find end of Box inset.")
1931 k = find_token(document.body, "status", i + 1, j)
1933 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1936 status = document.body[k]
1937 l = find_default_layout(document, i + 1, j)
1939 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1942 m = find_token(document.body, "\\end_layout", i + 1, j)
1944 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1947 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1948 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1949 if ibox == -1 and pbox == -1:
1950 document.body[i] = document.body[i].replace(
1951 "\\begin_inset Box", "\\begin_inset Note"
1953 del document.body[i + 1 : k]
1955 document.body[i] = document.body[i].replace(
1956 "\\begin_inset Box Shaded", "\\begin_inset Box Frameless"
1960 "\\begin_inset Note Shaded",
1962 "\\begin_layout Standard",
1964 document.body[l : l + 1] = subst1
1965 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1966 document.body[m : m + 1] = subst2
1970 def revert_slash(document):
1971 "Revert \\SpecialChar \\slash{} to ERT"
1973 while i < len(document.body):
1974 m = re.match(r"(.*)\\SpecialChar \\slash{}(.*)", document.body[i])
1980 "\\begin_inset ERT",
1983 "\\begin_layout Standard",
1994 document.body[i : i + 1] = subst
2000 def revert_nobreakdash(document):
2001 "Revert \\SpecialChar \\nobreakdash- to ERT"
2003 while i < len(document.body):
2004 m = re.match(r"(.*)\\SpecialChar \\nobreakdash-(.*)", document.body[i])
2010 "\\begin_inset ERT",
2013 "\\begin_layout Standard",
2024 document.body[i : i + 1] = subst
2026 j = find_token(document.header, "\\use_amsmath", 0)
2028 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
2031 document.header[j] = "\\use_amsmath 2"
2036 # Returns number of lines added/removed
2037 def revert_nocite_key(body, start, end):
2038 'key "..." -> \nocite{...}'
2039 r = re.compile(r'^key "(.*)"')
2043 m = r.match(body[i])
2045 body[i : i + 1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
2046 j += 1 # because we added a line
2047 i += 2 # skip that line
2050 j -= 1 # because we deleted a line
2051 # no need to change i, since it now points to the next line
2055 def revert_nocite(document):
2056 "Revert LatexCommand nocite to ERT"
2059 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
2062 if document.body[i + 1] != "LatexCommand nocite":
2063 # note that we already incremented i
2066 insetEnd = find_end_of_inset(document.body, i)
2068 # this should not happen
2069 document.warning("End of CommandInset citation not found in revert_nocite!")
2072 paramLocation = i + 2 # start of the inset's parameters
2074 document.body[i : i + 2] = [
2075 "\\begin_inset ERT",
2078 "\\begin_layout Standard",
2080 # that added two lines
2083 # print insetEnd, document.body[i: insetEnd + 1]
2084 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
2085 # print insetEnd, document.body[i: insetEnd + 1]
2086 document.body.insert(insetEnd, "\\end_layout")
2087 document.body.insert(insetEnd + 1, "")
2091 def revert_btprintall(document):
2092 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
2093 i = find_token(document.header, "\\use_bibtopic", 0)
2095 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
2097 if get_value(document.header, "\\use_bibtopic", 0) == "false":
2099 while i < len(document.body):
2100 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
2103 j = find_end_of_inset(document.body, i + 1)
2105 # this should not happen
2106 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
2107 j = len(document.body)
2108 # this range isn't really right, but it should be OK, since we shouldn't
2109 # see more than one matching line in each inset
2111 for k in range(i, j):
2112 if document.body[k] == 'btprint "btPrintAll"':
2113 del document.body[k]
2115 "\\begin_inset ERT",
2118 "\\begin_layout Standard",
2125 document.body[i:i] = subst
2126 addlines = addedlines + len(subst) - 1
2130 def revert_bahasam(document):
2131 "Set language Bahasa Malaysia to Bahasa Indonesia"
2133 if document.language == "bahasam":
2134 document.language = "bahasa"
2135 i = find_token(document.header, "\\language", 0)
2137 document.header[i] = "\\language bahasa"
2140 j = find_token(document.body, "\\lang bahasam", j)
2143 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
2147 def revert_interlingua(document):
2148 "Set language Interlingua to English"
2150 if document.language == "interlingua":
2151 document.language = "english"
2152 i = find_token(document.header, "\\language", 0)
2154 document.header[i] = "\\language english"
2157 j = find_token(document.body, "\\lang interlingua", j)
2160 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
2164 def revert_serbianlatin(document):
2165 "Set language Serbian-Latin to Croatian"
2167 if document.language == "serbian-latin":
2168 document.language = "croatian"
2169 i = find_token(document.header, "\\language", 0)
2171 document.header[i] = "\\language croatian"
2174 j = find_token(document.body, "\\lang serbian-latin", j)
2177 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
2181 def revert_rotfloat(document):
2182 "Revert sideways custom floats."
2185 # whitespace intended (exclude \\begin_inset FloatList)
2186 i = find_token(document.body, "\\begin_inset Float ", i)
2189 line = document.body[i]
2190 r = re.compile(r"\\begin_inset Float (.*)$")
2193 document.warning("Unable to match line " + str(i) + " of body!")
2196 floattype = m.group(1)
2197 if floattype == "figure" or floattype == "table":
2200 j = find_end_of_inset(document.body, i)
2203 "Malformed lyx document: Missing '\\end_inset' in revert_rotfloat."
2208 if get_value(document.body, "sideways", i, j) == "false":
2211 l = find_default_layout(document, i + 1, j)
2213 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2217 "\\begin_layout Standard",
2218 "\\begin_inset ERT",
2221 "\\begin_layout Standard",
2226 "end{sideways" + floattype + "}",
2231 document.body[j : j + 1] = subst
2232 addedLines = len(subst) - 1
2233 del document.body[i + 1 : l]
2234 addedLines -= (l - 1) - (i + 1)
2236 "\\begin_inset ERT",
2239 "\\begin_layout Standard",
2243 "begin{sideways" + floattype + "}",
2251 document.body[i : i + 1] = subst
2252 addedLines += len(subst) - 1
2253 if floattype == "algorithm":
2257 "% Commands inserted by lyx2lyx for sideways algorithm float",
2258 "\\usepackage{rotfloat}",
2259 "\\floatstyle{ruled}",
2260 "\\newfloat{algorithm}{tbp}{loa}",
2261 "\\floatname{algorithm}{Algorithm}",
2266 "Cannot create preamble definition for custom float" + floattype + "."
2271 def revert_widesideways(document):
2272 "Revert wide sideways floats."
2275 # whitespace intended (exclude \\begin_inset FloatList)
2276 i = find_token(document.body, "\\begin_inset Float ", i)
2279 line = document.body[i]
2280 r = re.compile(r"\\begin_inset Float (.*)$")
2283 document.warning("Unable to match line " + str(i) + " of body!")
2286 floattype = m.group(1)
2287 if floattype != "figure" and floattype != "table":
2290 j = find_end_of_inset(document.body, i)
2293 "Malformed lyx document: Missing '\\end_inset' in revert_widesideways."
2298 get_value(document.body, "sideways", i, j) == "false"
2299 or get_value(document.body, "wide", i, j) == "false"
2303 l = find_default_layout(document, i + 1, j)
2305 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2309 "\\begin_layout Standard",
2310 "\\begin_inset ERT",
2313 "\\begin_layout Standard",
2317 "end{sideways" + floattype + "*}",
2322 document.body[j : j + 1] = subst
2323 addedLines = len(subst) - 1
2324 del document.body[i + 1 : l - 1]
2325 addedLines -= (l - 1) - (i + 1)
2327 "\\begin_inset ERT",
2330 "\\begin_layout Standard",
2334 "begin{sideways" + floattype + "*}",
2342 document.body[i : i + 1] = subst
2343 addedLines += len(subst) - 1
2344 add_to_preamble(document, ["\\usepackage{rotfloat}\n"])
2348 def revert_inset_embedding(document, type):
2349 "Remove embed tag from certain type of insets"
2352 i = find_token(document.body, "\\begin_inset %s" % type, i)
2355 j = find_end_of_inset(document.body, i)
2358 "Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding."
2362 k = find_token(document.body, "\tembed", i, j)
2364 k = find_token(document.body, "embed", i, j)
2366 del document.body[k]
2370 def revert_external_embedding(document):
2371 "Remove embed tag from external inset"
2372 revert_inset_embedding(document, "External")
2375 def convert_subfig(document):
2376 "Convert subfigures to subfloats."
2380 i = find_token(document.body, "\\begin_inset Graphics", i)
2383 endInset = find_end_of_inset(document.body, i)
2385 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2388 k = find_token(document.body, "\tsubcaption", i, endInset)
2392 l = find_token(document.body, "\tsubcaptionText", i, endInset)
2396 caption = document.body[l][16:].strip('"')
2397 del document.body[l]
2399 del document.body[k]
2403 "\\begin_inset Float figure",
2408 "\\begin_layout Plain Layout",
2409 "\\begin_inset Caption",
2411 "\\begin_layout Plain Layout",
2413 + latex2lyx(caption, False)
2421 "\\begin_layout Plain Layout",
2424 document.body[i:i] = subst
2425 addedLines += len(subst)
2426 endInset += addedLines
2427 subst = ["", "\\end_inset", "", "\\end_layout"]
2428 document.body[endInset:endInset] = subst
2429 addedLines += len(subst)
2433 def revert_subfig(document):
2437 # whitespace intended (exclude \\begin_inset FloatList)
2438 i = find_tokens(document.body, ["\\begin_inset Float ", "\\begin_inset Wrap"], i)
2444 j = find_end_of_inset(document.body, i)
2447 "Malformed lyx document: Missing '\\end_inset' (float) at line "
2448 + str(i + len(document.header))
2452 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2454 continue # this will get us back to the outer loop, since j == -1
2455 # look for embedded float (= subfloat)
2456 # whitespace intended (exclude \\begin_inset FloatList)
2457 k = find_token(document.body, "\\begin_inset Float ", i + 1, j)
2460 # is the subfloat aligned?
2461 al = find_token(document.body, "\\align ", k - 1, j)
2465 if get_value(document.body, "\\align", al) == "center":
2466 alignment_beg = "\\backslash\nbegin{centering}"
2467 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2468 elif get_value(document.body, "\\align", al) == "left":
2469 alignment_beg = "\\backslash\nbegin{raggedright}"
2470 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2471 elif get_value(document.body, "\\align", al) == "right":
2472 alignment_beg = "\\backslash\nbegin{raggedleft}"
2473 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2474 l = find_end_of_inset(document.body, k)
2477 "Malformed lyx document: Missing '\\end_inset' (embedded float)."
2481 continue # escape to the outer loop
2482 m = find_default_layout(document, k + 1, l)
2484 cap = find_token(document.body, "\\begin_inset Caption", k + 1, l)
2489 capend = find_end_of_inset(document.body, cap)
2491 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2495 lbl = find_token(document.body, "\\begin_inset CommandInset label", cap, capend)
2497 lblend = find_end_of_inset(document.body, lbl + 1)
2500 "Malformed lyx document: Missing '\\end_inset' (label)."
2503 for line in document.body[lbl : lblend + 1]:
2504 if line.startswith("name "):
2505 label = line.split()[1].strip('"')
2512 opt = find_token(document.body, "\\begin_inset OptArg", cap, capend)
2514 optend = find_end_of_inset(document.body, opt)
2517 "Malformed LyX document: Missing '\\end_inset' (OptArg)."
2520 optc = find_default_layout(document, opt, optend)
2523 "Malformed LyX document: Missing `\\begin_layout' in Float inset."
2526 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2527 for line in document.body[optc:optcend]:
2528 if not line.startswith("\\"):
2529 shortcap += line.strip()
2533 for line in document.body[cap:capend]:
2534 if line in document.body[lbl:lblend]:
2536 elif line in document.body[opt:optend]:
2540 caption += lyxline2latex(document, line, inert)
2542 caption += "\n\\backslash\nlabel{" + label + "}"
2544 "\\begin_layout PlainLayout\n\\begin_inset ERT\nstatus collapsed\n\n"
2545 "\\begin_layout PlainLayout\n\n}"
2547 + "\n\\end_layout\n\n\\end_inset\n\n"
2548 "\\end_layout\n\n\\begin_layout PlainLayout\n"
2550 subst = subst.split("\n")
2551 document.body[l : l + 1] = subst
2552 addedLines = len(subst) - 1
2553 # this is before l and so is unchanged by the multiline insertion
2555 del document.body[cap : capend + 1]
2556 addedLines -= capend + 1 - cap
2557 del document.body[k + 1 : m - 1]
2558 addedLines -= m - 1 - (k + 1)
2560 "\\begin_inset ERT\nstatus collapsed\n\n"
2561 "\\begin_layout PlainLayout\n\n" + alignment_beg + "\n\\backslash\n"
2564 if len(shortcap) > 0:
2565 insertion = insertion + "[" + shortcap + "]"
2566 if len(caption) > 0:
2567 insertion = insertion + "[" + caption + "]"
2568 insertion = insertion + "{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n"
2569 insertion = insertion.split("\n")
2570 document.body[k : k + 1] = insertion
2571 addedLines += len(insertion) - 1
2572 al = find_token(document.body, "\\align ", k - 1, j + addedLines)
2574 del document.body[al]
2576 add_to_preamble(document, ["\\usepackage{subfig}\n"])
2580 def revert_wrapplacement(document):
2581 "Revert placement options wrap floats (wrapfig)."
2584 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2587 e = find_end_of_inset(document.body, i)
2588 j = find_token(document.body, "placement", i + 1, e)
2591 "Malformed LyX document: Couldn't find placement parameter of wrap float."
2595 r = re.compile("placement (o|i|l|r|O|I|L|R)")
2596 m = r.match(document.body[j])
2598 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2600 document.body[j] = "placement " + m.group(1).lower()
2604 def remove_extra_embedded_files(document):
2605 r"Remove \extra_embedded_files from buffer params"
2606 i = find_token(document.header, "\\extra_embedded_files", 0)
2609 document.header.pop(i)
2612 def convert_spaceinset(document):
2613 "Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset'"
2615 while i < len(document.body):
2616 m = re.match(r"(.*)\\InsetSpace (.*)", document.body[i])
2620 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2621 document.body[i : i + 1] = subst
2627 def revert_spaceinset(document):
2628 "Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo'"
2631 i = find_token(document.body, "\\begin_inset Space", i)
2634 j = find_end_of_inset(document.body, i)
2636 document.warning("Malformed LyX document: Could not find end of space inset.")
2639 document.body[i] = document.body[i].replace("\\begin_inset Space", "\\InsetSpace")
2640 del document.body[j]
2643 def convert_hfill(document):
2644 "Convert hfill to space inset"
2647 i = find_token(document.body, "\\hfill", i)
2650 subst = document.body[i].replace(
2651 "\\hfill", "\n\\begin_inset Space \\hfill{}\n\\end_inset"
2653 subst = subst.split("\n")
2654 document.body[i : i + 1] = subst
2658 def revert_hfills(document):
2659 "Revert \\hfill commands"
2660 hfill = re.compile(r"\\hfill")
2661 dotfill = re.compile(r"\\dotfill")
2662 hrulefill = re.compile(r"\\hrulefill")
2665 i = find_token(document.body, "\\InsetSpace", i)
2668 if hfill.search(document.body[i]):
2669 document.body[i] = document.body[i].replace("\\InsetSpace \\hfill{}", "\\hfill")
2672 if dotfill.search(document.body[i]):
2673 subst = document.body[i].replace(
2674 "\\InsetSpace \\dotfill{}",
2675 "\\begin_inset ERT\nstatus collapsed\n\n"
2676 "\\begin_layout Standard\n\n\n\\backslash\n"
2677 "dotfill{}\n\\end_layout\n\n\\end_inset\n\n",
2679 subst = subst.split("\n")
2680 document.body[i : i + 1] = subst
2683 if hrulefill.search(document.body[i]):
2684 subst = document.body[i].replace(
2685 "\\InsetSpace \\hrulefill{}",
2686 "\\begin_inset ERT\nstatus collapsed\n\n"
2687 "\\begin_layout Standard\n\n\n\\backslash\n"
2688 "hrulefill{}\n\\end_layout\n\n\\end_inset\n\n",
2690 subst = subst.split("\n")
2691 document.body[i : i + 1] = subst
2697 def revert_hspace(document):
2698 "Revert \\InsetSpace \\hspace{} to ERT"
2700 hspace = re.compile(r"\\hspace{}")
2701 hstar = re.compile(r"\\hspace\*{}")
2703 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2706 length = get_value(document.body, "\\length", i + 1)
2708 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2710 del document.body[i + 1]
2712 if hstar.search(document.body[i]):
2713 subst = document.body[i].replace(
2714 "\\InsetSpace \\hspace*{}",
2715 "\\begin_inset ERT\nstatus collapsed\n\n"
2716 "\\begin_layout Standard\n\n\n\\backslash\n"
2717 "hspace*{" + length + "}\n\\end_layout\n\n\\end_inset\n\n",
2719 subst = subst.split("\n")
2720 document.body[i : i + 1] = subst
2721 addedLines += len(subst) - 1
2724 if hspace.search(document.body[i]):
2725 subst = document.body[i].replace(
2726 "\\InsetSpace \\hspace{}",
2727 "\\begin_inset ERT\nstatus collapsed\n\n"
2728 "\\begin_layout Standard\n\n\n\\backslash\n"
2729 "hspace{" + length + "}\n\\end_layout\n\n\\end_inset\n\n",
2731 subst = subst.split("\n")
2732 document.body[i : i + 1] = subst
2733 addedLines += len(subst) - 1
2739 def revert_protected_hfill(document):
2740 "Revert \\begin_inset Space \\hspace*{\\fill} to ERT"
2743 i = find_token(document.body, "\\begin_inset Space \\hspace*{\\fill}", i)
2746 j = find_end_of_inset(document.body, i)
2748 document.warning("Malformed LyX document: Could not find end of space inset.")
2751 del document.body[j]
2752 subst = document.body[i].replace(
2753 "\\begin_inset Space \\hspace*{\\fill}",
2754 "\\begin_inset ERT\nstatus collapsed\n\n"
2755 "\\begin_layout Standard\n\n\n\\backslash\n"
2756 "hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n",
2758 subst = subst.split("\n")
2759 document.body[i : i + 1] = subst
2763 def revert_leftarrowfill(document):
2764 "Revert \\begin_inset Space \\leftarrowfill{} to ERT"
2767 i = find_token(document.body, "\\begin_inset Space \\leftarrowfill{}", i)
2770 j = find_end_of_inset(document.body, i)
2772 document.warning("Malformed LyX document: Could not find end of space inset.")
2775 del document.body[j]
2776 subst = document.body[i].replace(
2777 "\\begin_inset Space \\leftarrowfill{}",
2778 "\\begin_inset ERT\nstatus collapsed\n\n"
2779 "\\begin_layout Standard\n\n\n\\backslash\n"
2780 "leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n",
2782 subst = subst.split("\n")
2783 document.body[i : i + 1] = subst
2787 def revert_rightarrowfill(document):
2788 "Revert \\begin_inset Space \\rightarrowfill{} to ERT"
2791 i = find_token(document.body, "\\begin_inset Space \\rightarrowfill{}", i)
2794 j = find_end_of_inset(document.body, i)
2796 document.warning("Malformed LyX document: Could not find end of space inset.")
2799 del document.body[j]
2800 subst = document.body[i].replace(
2801 "\\begin_inset Space \\rightarrowfill{}",
2802 "\\begin_inset ERT\nstatus collapsed\n\n"
2803 "\\begin_layout Standard\n\n\n\\backslash\n"
2804 "rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n",
2806 subst = subst.split("\n")
2807 document.body[i : i + 1] = subst
2811 def revert_upbracefill(document):
2812 "Revert \\begin_inset Space \\upbracefill{} to ERT"
2815 i = find_token(document.body, "\\begin_inset Space \\upbracefill{}", i)
2818 j = find_end_of_inset(document.body, i)
2820 document.warning("Malformed LyX document: Could not find end of space inset.")
2823 del document.body[j]
2824 subst = document.body[i].replace(
2825 "\\begin_inset Space \\upbracefill{}",
2826 "\\begin_inset ERT\nstatus collapsed\n\n"
2827 "\\begin_layout Standard\n\n\n\\backslash\n"
2828 "upbracefill{}\n\\end_layout\n\n\\end_inset\n\n",
2830 subst = subst.split("\n")
2831 document.body[i : i + 1] = subst
2835 def revert_downbracefill(document):
2836 "Revert \\begin_inset Space \\downbracefill{} to ERT"
2839 i = find_token(document.body, "\\begin_inset Space \\downbracefill{}", i)
2842 j = find_end_of_inset(document.body, i)
2844 document.warning("Malformed LyX document: Could not find end of space inset.")
2847 del document.body[j]
2848 subst = document.body[i].replace(
2849 "\\begin_inset Space \\downbracefill{}",
2850 "\\begin_inset ERT\nstatus collapsed\n\n"
2851 "\\begin_layout Standard\n\n\n\\backslash\n"
2852 "downbracefill{}\n\\end_layout\n\n\\end_inset\n\n",
2854 subst = subst.split("\n")
2855 document.body[i : i + 1] = subst
2859 def revert_local_layout(document):
2860 "Revert local layout headers."
2863 i = find_token(document.header, "\\begin_local_layout", i)
2866 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2868 # this should not happen
2870 document.header[i : j + 1] = []
2873 def convert_pagebreaks(document):
2874 "Convert inline Newpage insets to new format"
2877 i = find_token(document.body, "\\newpage", i)
2880 document.body[i : i + 1] = ["\\begin_inset Newpage newpage", "\\end_inset"]
2883 i = find_token(document.body, "\\pagebreak", i)
2886 document.body[i : i + 1] = ["\\begin_inset Newpage pagebreak", "\\end_inset"]
2889 i = find_token(document.body, "\\clearpage", i)
2892 document.body[i : i + 1] = ["\\begin_inset Newpage clearpage", "\\end_inset"]
2895 i = find_token(document.body, "\\cleardoublepage", i)
2898 document.body[i : i + 1] = [
2899 "\\begin_inset Newpage cleardoublepage",
2904 def revert_pagebreaks(document):
2905 "Revert \\begin_inset Newpage to previous inline format"
2908 i = find_token(document.body, "\\begin_inset Newpage", i)
2911 j = find_end_of_inset(document.body, i)
2913 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2916 del document.body[j]
2917 document.body[i] = document.body[i].replace(
2918 "\\begin_inset Newpage newpage", "\\newpage"
2920 document.body[i] = document.body[i].replace(
2921 "\\begin_inset Newpage pagebreak", "\\pagebreak"
2923 document.body[i] = document.body[i].replace(
2924 "\\begin_inset Newpage clearpage", "\\clearpage"
2926 document.body[i] = document.body[i].replace(
2927 "\\begin_inset Newpage cleardoublepage", "\\cleardoublepage"
2931 def convert_linebreaks(document):
2932 "Convert inline Newline insets to new format"
2935 i = find_token(document.body, "\\newline", i)
2938 document.body[i : i + 1] = ["\\begin_inset Newline newline", "\\end_inset"]
2941 i = find_token(document.body, "\\linebreak", i)
2944 document.body[i : i + 1] = ["\\begin_inset Newline linebreak", "\\end_inset"]
2947 def revert_linebreaks(document):
2948 "Revert \\begin_inset Newline to previous inline format"
2951 i = find_token(document.body, "\\begin_inset Newline", i)
2954 j = find_end_of_inset(document.body, i)
2956 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2959 del document.body[j]
2960 document.body[i] = document.body[i].replace(
2961 "\\begin_inset Newline newline", "\\newline"
2963 document.body[i] = document.body[i].replace(
2964 "\\begin_inset Newline linebreak", "\\linebreak"
2968 def convert_japanese_plain(document):
2969 "Set language japanese-plain to japanese"
2971 if document.language == "japanese-plain":
2972 document.language = "japanese"
2973 i = find_token(document.header, "\\language", 0)
2975 document.header[i] = "\\language japanese"
2978 j = find_token(document.body, "\\lang japanese-plain", j)
2981 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2985 def revert_pdfpages(document):
2986 "Revert pdfpages external inset to ERT"
2989 i = find_token(document.body, "\\begin_inset External", i)
2992 j = find_end_of_inset(document.body, i)
2995 "Malformed lyx document: Missing '\\end_inset' in revert_pdfpages."
2999 if get_value(document.body, "template", i, j) == "PDFPages":
3000 filename = get_value(document.body, "filename", i, j)
3002 r = re.compile(r"\textra PDFLaTeX \"(.*)\"$")
3003 for k in range(i, j):
3004 m = r.match(document.body[k])
3007 angle = get_value(document.body, "rotateAngle", i, j)
3008 width = get_value(document.body, "width", i, j)
3009 height = get_value(document.body, "height", i, j)
3010 scale = get_value(document.body, "scale", i, j)
3011 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
3015 options += ",angle=" + angle
3017 options += "angle=" + angle
3020 options += ",width=" + convert_len(width)
3022 options += "width=" + convert_len(width)
3025 options += ",height=" + convert_len(height)
3027 options += "height=" + convert_len(height)
3030 options += ",scale=" + scale
3032 options += "scale=" + scale
3033 if keepAspectRatio != "":
3035 options += ",keepaspectratio"
3037 options += "keepaspectratio"
3039 options = "[" + options + "]"
3040 del document.body[i + 1 : j + 1]
3041 document.body[i : i + 1] = [
3042 "\\begin_inset ERT",
3045 "\\begin_layout Standard",
3048 "includepdf" + options + "{" + filename + "}",
3053 add_to_preamble(document, ["\\usepackage{pdfpages}\n"])
3059 def revert_mexican(document):
3060 "Set language Spanish(Mexico) to Spanish"
3062 if document.language == "spanish-mexico":
3063 document.language = "spanish"
3064 i = find_token(document.header, "\\language", 0)
3066 document.header[i] = "\\language spanish"
3069 j = find_token(document.body, "\\lang spanish-mexico", j)
3072 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
3076 def remove_embedding(document):
3077 "Remove embed tag from all insets"
3078 revert_inset_embedding(document, "Graphics")
3079 revert_inset_embedding(document, "External")
3080 revert_inset_embedding(document, "CommandInset include")
3081 revert_inset_embedding(document, "CommandInset bibtex")
3084 def revert_master(document):
3085 "Remove master param"
3086 i = find_token(document.header, "\\master", 0)
3088 del document.header[i]
3091 def revert_graphics_group(document):
3092 "Revert group information from graphics insets"
3095 i = find_token(document.body, "\\begin_inset Graphics", i)
3098 j = find_end_of_inset(document.body, i)
3101 "Malformed lyx document: Missing '\\end_inset' in revert_graphics_group."
3105 k = find_token(document.body, " groupId", i, j)
3109 del document.body[k]
3113 def update_apa_styles(document):
3114 "Replace obsolete styles"
3116 if document.textclass != "apa":
3120 "Acknowledgments": "Acknowledgements",
3121 "Section*": "Section",
3122 "Subsection*": "Subsection",
3123 "Subsubsection*": "Subsubsection",
3124 "Paragraph*": "Paragraph",
3125 "Subparagraph*": "Subparagraph",
3129 i = find_token(document.body, "\\begin_layout", i)
3133 layout = document.body[i][14:]
3134 if layout in obsoletedby:
3135 document.body[i] = "\\begin_layout " + obsoletedby[layout]
3140 def convert_paper_sizes(document):
3141 "exchange size options legalpaper and executivepaper to correct order"
3142 # routine is needed to fix http://www.lyx.org/trac/ticket/4868
3145 i = find_token(document.header, "\\papersize executivepaper", 0)
3147 document.header[i] = "\\papersize legalpaper"
3149 j = find_token(document.header, "\\papersize legalpaper", 0)
3151 document.header[j] = "\\papersize executivepaper"
3154 def revert_paper_sizes(document):
3155 "exchange size options legalpaper and executivepaper to correct order"
3158 i = find_token(document.header, "\\papersize executivepaper", 0)
3160 document.header[i] = "\\papersize legalpaper"
3162 j = find_token(document.header, "\\papersize legalpaper", 0)
3164 document.header[j] = "\\papersize executivepaper"
3167 def convert_InsetSpace(document):
3168 "Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
3171 i = find_token(document.body, "\\begin_inset Space", i)
3174 document.body[i] = document.body[i].replace(
3175 "\\begin_inset Space", "\\begin_inset space"
3179 def revert_InsetSpace(document):
3180 "Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
3183 i = find_token(document.body, "\\begin_inset space", i)
3186 document.body[i] = document.body[i].replace(
3187 "\\begin_inset space", "\\begin_inset Space"
3191 def convert_display_enum(document):
3192 "Convert 'display foo' to 'display false/true'"
3195 i = find_token(document.body, "\tdisplay", i)
3198 val = get_value(document.body, "display", i)
3200 document.body[i] = document.body[i].replace("none", "false")
3201 if val == "default":
3202 document.body[i] = document.body[i].replace("default", "true")
3203 if val == "monochrome":
3204 document.body[i] = document.body[i].replace("monochrome", "true")
3205 if val == "grayscale":
3206 document.body[i] = document.body[i].replace("grayscale", "true")
3208 document.body[i] = document.body[i].replace("color", "true")
3209 if val == "preview":
3210 document.body[i] = document.body[i].replace("preview", "true")
3214 def revert_display_enum(document):
3215 "Revert 'display false/true' to 'display none/color'"
3218 i = find_token(document.body, "\tdisplay", i)
3221 val = get_value(document.body, "display", i)
3223 document.body[i] = document.body[i].replace("false", "none")
3225 document.body[i] = document.body[i].replace("true", "default")
3229 def remove_fontsCJK(document):
3230 "Remove font_cjk param"
3231 i = find_token(document.header, "\\font_cjk", 0)
3233 del document.header[i]
3236 def convert_plain_layout(document):
3237 "Convert 'PlainLayout' to 'Plain Layout'"
3240 i = find_token(document.body, "\\begin_layout PlainLayout", i)
3243 document.body[i] = document.body[i].replace(
3244 "\\begin_layout PlainLayout", "\\begin_layout Plain Layout"
3249 def revert_plain_layout(document):
3250 "Revert 'Plain Layout' to 'PlainLayout'"
3253 i = find_token(document.body, "\\begin_layout Plain Layout", i)
3256 document.body[i] = document.body[i].replace(
3257 "\\begin_layout Plain Layout", "\\begin_layout PlainLayout"
3262 def revert_plainlayout(document):
3263 "Revert 'PlainLayout' to 'Standard'"
3266 i = find_token(document.body, "\\begin_layout PlainLayout", i)
3269 # This will be incorrect for some document classes, since Standard is not always
3270 # the default. But (a) it is probably the best we can do and (b) it will actually
3271 # work, in fact, since an unknown layout will be converted to default.
3272 document.body[i] = document.body[i].replace(
3273 "\\begin_layout PlainLayout", "\\begin_layout Standard"
3278 def revert_polytonicgreek(document):
3279 "Set language polytonic Greek to Greek"
3281 if document.language == "polutonikogreek":
3282 document.language = "greek"
3283 i = find_token(document.header, "\\language", 0)
3285 document.header[i] = "\\language greek"
3288 j = find_token(document.body, "\\lang polutonikogreek", j)
3291 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
3295 def revert_removed_modules(document):
3298 i = find_token(document.header, "\\begin_remove_modules", i)
3301 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
3303 # this should not happen
3305 document.header[i : j + 1] = []
3308 def add_plain_layout(document):
3311 i = find_token(document.body, "\\begin_layout", i)
3314 if len(document.body[i].split()) == 1:
3315 document.body[i] = "\\begin_layout Plain Layout"
3319 def revert_tabulators(document):
3320 "Revert tabulators to 4 spaces"
3323 i = find_token(document.body, "\t", i)
3326 document.body[i] = document.body[i].replace("\t", " ")
3330 def revert_tabsize(document):
3331 "Revert the tabsize parameter of listings"
3335 # either it is the only parameter
3336 i = find_token(document.body, 'lstparams "tabsize=4"', i)
3338 del document.body[i]
3340 j = find_token(document.body, "lstparams", j)
3343 pos = document.body[j].find(",tabsize=")
3344 document.body[j] = document.body[j][:pos] + '"'
3349 def revert_mongolian(document):
3350 "Set language Mongolian to English"
3352 if document.language == "mongolian":
3353 document.language = "english"
3354 i = find_token(document.header, "\\language", 0)
3356 document.header[i] = "\\language english"
3359 j = find_token(document.body, "\\lang mongolian", j)
3362 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
3366 def revert_default_options(document):
3367 "Remove param use_default_options"
3368 i = find_token(document.header, "\\use_default_options", 0)
3370 del document.header[i]
3373 def convert_default_options(document):
3374 "Add param use_default_options and set it to false"
3375 i = find_token(document.header, "\\textclass", 0)
3377 document.warning("Malformed LyX document: Missing `\\textclass'.")
3379 document.header.insert(i, "\\use_default_options false")
3382 def revert_backref_options(document):
3383 "Revert option pdf_backref=page to pagebackref"
3384 i = find_token(document.header, "\\pdf_backref page", 0)
3386 document.header[i] = "\\pdf_pagebackref true"
3389 def convert_backref_options(document):
3390 "We have changed the option pagebackref to backref=true"
3391 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3393 document.header[i] = "\\pdf_backref page"
3394 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3396 del document.header[j]
3397 # backref=true was not a valid option, we meant backref=section
3398 k = find_token(document.header, "\\pdf_backref true", 0)
3399 if k != -1 and i != -1:
3400 del document.header[k]
3401 elif k != -1 and j != -1:
3402 document.header[k] = "\\pdf_backref section"
3405 def convert_charstyle_element(document):
3406 "Convert CharStyle to Element for docbook backend"
3407 if document.backend != "docbook":
3411 i = find_token(document.body, "\\begin_inset Flex CharStyle:", i)
3414 document.body[i] = document.body[i].replace(
3415 "\\begin_inset Flex CharStyle:", "\\begin_inset Flex Element:"
3419 def revert_charstyle_element(document):
3420 "Convert Element to CharStyle for docbook backend"
3421 if document.backend != "docbook":
3425 i = find_token(document.body, "\\begin_inset Flex Element:", i)
3428 document.body[i] = document.body[i].replace(
3429 "\\begin_inset Flex Element:", "\\begin_inset Flex CharStyle:"
3437 supported_versions = ["1.6.0", "1.6"]
3439 [277, [fix_wrong_tables]],
3440 [278, [close_begin_deeper]],
3441 [279, [long_charstyle_names]],
3442 [280, [axe_show_label]],
3445 [283, [convert_flex]],
3449 [287, [convert_wrapfig_options]],
3450 [288, [convert_inset_command]],
3451 [289, [convert_latexcommand_index]],
3454 [292, [convert_japanese_cjk]],
3456 [294, [convert_pdf_options]],
3457 [295, [convert_htmlurl, convert_url]],
3458 [296, [convert_include]],
3459 [297, [convert_usorbian]],
3460 [298, [convert_macro_global]],
3465 [303, [convert_serbocroatian]],
3466 [304, [convert_framed_notes]],
3473 [311, [convert_ams_classes]],
3475 [313, [convert_module_names]],
3478 [316, [convert_subfig]],
3481 [319, [convert_spaceinset, convert_hfill]],
3483 [321, [convert_tablines]],
3484 [322, [convert_plain_layout]],
3485 [323, [convert_pagebreaks]],
3486 [324, [convert_linebreaks]],
3487 [325, [convert_japanese_plain]],
3490 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3493 [331, [convert_ltcaption]],
3495 [333, [update_apa_styles]],
3496 [334, [convert_paper_sizes]],
3497 [335, [convert_InsetSpace]],
3499 [337, [convert_display_enum]],
3502 [340, [add_plain_layout]],
3505 [343, [convert_default_options]],
3506 [344, [convert_backref_options]],
3507 [345, [convert_charstyle_element]],
3511 [344, [revert_charstyle_element]],
3512 [343, [revert_backref_options]],
3513 [342, [revert_default_options]],
3514 [341, [revert_mongolian]],
3515 [340, [revert_tabulators, revert_tabsize]],
3517 [338, [revert_removed_modules]],
3518 [337, [revert_polytonicgreek]],
3519 [336, [revert_display_enum]],
3520 [335, [remove_fontsCJK]],
3521 [334, [revert_InsetSpace]],
3522 [333, [revert_paper_sizes]],
3524 [331, [revert_graphics_group]],
3525 [330, [revert_ltcaption]],
3529 revert_leftarrowfill,
3530 revert_rightarrowfill,
3532 revert_downbracefill,
3535 [328, [revert_master]],
3537 [326, [revert_mexican]],
3538 [325, [revert_pdfpages]],
3540 [323, [revert_linebreaks]],
3541 [322, [revert_pagebreaks]],
3542 [321, [revert_local_layout, revert_plain_layout]],
3543 [320, [revert_tablines]],
3544 [319, [revert_protected_hfill]],
3545 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3546 [317, [remove_extra_embedded_files]],
3547 [316, [revert_wrapplacement]],
3548 [315, [revert_subfig]],
3549 [314, [revert_colsep, revert_plainlayout]],
3551 [312, [revert_module_names]],
3552 [311, [revert_rotfloat, revert_widesideways]],
3553 [310, [revert_external_embedding]],
3554 [309, [revert_btprintall]],
3555 [308, [revert_nocite]],
3556 [307, [revert_serbianlatin]],
3557 [306, [revert_slash, revert_nobreakdash]],
3558 [305, [revert_interlingua]],
3559 [304, [revert_bahasam]],
3560 [303, [revert_framed_notes]],
3562 [301, [revert_latin, revert_samin]],
3563 [300, [revert_linebreak]],
3564 [299, [revert_pagebreak]],
3565 [298, [revert_hyperlinktype]],
3566 [297, [revert_macro_optional_params]],
3567 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3568 [295, [revert_include]],
3569 [294, [revert_href, revert_url]],
3570 [293, [revert_pdf_options_2]],
3571 [292, [revert_inset_info]],
3572 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3573 [290, [revert_vietnamese]],
3574 [289, [revert_wraptable]],
3575 [288, [revert_latexcommand_index]],
3576 [287, [revert_inset_command]],
3577 [286, [revert_wrapfig_options]],
3578 [285, [revert_pdf_options]],
3579 [284, [remove_inzip_options]],
3581 [282, [revert_flex]],
3583 [280, [revert_begin_modules]],
3584 [279, [revert_show_label]],
3585 [278, [revert_long_charstyle_names]],
3591 if __name__ == "__main__":