1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # Copyright (C) 2015 The LyX team
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 2.2"""
25 # Uncomment only what you need to import, please.
27 from lyx2lyx_tools import (add_to_preamble, put_cmd_in_ert, get_ert,
28 lyx2latex, lyx2verbatim, length_in_bp, convert_info_insets, insert_document_option)
30 from parser_tools import (check_token, del_complete_lines,
31 find_end_of_inset, find_end_of_layout, find_nonempty_line, find_re,
32 find_substring, find_token, find_token_backwards, get_containing_layout,
33 get_containing_inset, get_quoted_value, get_value, is_in_inset,
34 get_bool_value, set_bool_value)
37 ####################################################################
38 # Private helper functions
40 def revert_Argument_to_TeX_brace(document, line, endline, n, nmax, environment, opt, nolastopt):
42 Reverts an InsetArgument to TeX-code
44 revert_Argument_to_TeX_brace(document, LineOfBegin, LineOfEnd, StartArgument, EndArgument, isEnvironment, isOpt, notLastOpt)
45 LineOfBegin is the line of the \begin_layout or \begin_inset statement
46 LineOfEnd is the line of the \end_layout or \end_inset statement, if "0" is given, the end of the file is used instead
47 StartArgument is the number of the first argument that needs to be converted
48 EndArgument is the number of the last argument that needs to be converted or the last defined one
49 isEnvironment must be true, if the layout is for a LaTeX environment
50 isOpt must be true, if the argument is an optional one
51 notLastOpt must be true if the argument is mandatory and followed by optional ones
55 while lineArg != -1 and n < nmax + 1:
56 lineArg = find_token(document.body, "\\begin_inset Argument " + str(n), line)
57 if lineArg > endline and endline != 0:
60 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
61 # we have to assure that no other inset is in the Argument
62 beginInset = find_token(document.body, "\\begin_inset", beginPlain)
63 endInset = find_token(document.body, "\\end_inset", beginPlain)
66 while beginInset < endInset and beginInset != -1:
67 beginInset = find_token(document.body, "\\begin_inset", k)
68 endInset = find_token(document.body, "\\end_inset", l)
71 if environment == False:
73 document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}")
74 document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("{")
77 document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("]")
78 document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("[")
82 document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}")
83 document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("{")
86 document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("]")
87 document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("[")
93 ###############################################################################
95 ### Conversion and reversion routines
97 ###############################################################################
99 def convert_longtable_label_internal(document, forward):
101 Convert reference to "LongTableNoNumber" into "Unnumbered" if forward is True
104 old_reference = "\\begin_inset Caption LongTableNoNumber"
105 new_reference = "\\begin_inset Caption Unnumbered"
107 # if the purpose is to revert swap the strings roles
109 old_reference, new_reference = new_reference, old_reference
113 i = find_token(document.body, old_reference, i)
118 document.body[i] = new_reference
121 def convert_longtable_label(document):
122 convert_longtable_label_internal(document, True)
125 def revert_longtable_label(document):
126 convert_longtable_label_internal(document, False)
129 def convert_separator(document):
131 Convert layout separators to separator insets and add (LaTeX) paragraph
132 breaks in order to mimic previous LaTeX export.
135 parins = ["\\begin_inset Separator parbreak", "\\end_inset", ""]
136 parlay = ["\\begin_layout Standard", "\\begin_inset Separator parbreak",
137 "\\end_inset", "", "\\end_layout", ""]
139 "family" : "default",
140 "series" : "default",
149 i = find_token(document.body, "\\begin_deeper", i)
153 j = find_token_backwards(document.body, "\\end_layout", i-1)
155 # reset any text style before inserting the inset
156 lay = get_containing_layout(document.body, j-1)
158 content = "\n".join(document.body[lay[1]:lay[2]])
159 for val in list(sty_dict.keys()):
160 if content.find("\\%s" % val) != -1:
161 document.body[j:j] = ["\\%s %s" % (val, sty_dict[val])]
164 document.body[j:j] = parins
165 i = i + len(parins) + 1
171 i = find_token(document.body, "\\align", i)
175 lay = get_containing_layout(document.body, i)
176 if lay != False and lay[0] == "Plain Layout":
180 j = find_token_backwards(document.body, "\\end_layout", i-1)
182 # Very old LyX files do not have Plain Layout in insets (but Standard).
183 # So we additionally check here if there is no inset boundary
184 # between the previous layout and this one.
185 n = find_token(document.body, "\\end_inset", j, lay[1])
189 lay = get_containing_layout(document.body, j-1)
190 if lay != False and lay[0] == "Standard" \
191 and find_token(document.body, "\\align", lay[1], lay[2]) == -1 \
192 and find_token(document.body, "\\begin_inset VSpace", lay[1], lay[2]) == -1:
193 # reset any text style before inserting the inset
194 content = "\n".join(document.body[lay[1]:lay[2]])
195 for val in list(sty_dict.keys()):
196 if content.find("\\%s" % val) != -1:
197 document.body[j:j] = ["\\%s %s" % (val, sty_dict[val])]
200 document.body[j:j] = parins
201 i = i + len(parins) + 1
207 regexp = re.compile(r'^\\begin_layout (?:(-*)|(\s*))(Separator|EndOfSlide)(?:(-*)|(\s*))$', re.IGNORECASE)
211 i = find_re(document.body, regexp, i)
215 j = find_end_of_layout(document.body, i)
217 document.warning("Malformed LyX document: Missing `\\end_layout'.")
220 lay = get_containing_layout(document.body, j-1)
222 lines = document.body[lay[3]:lay[2]]
226 document.body[i:j+1] = parlay
228 document.body[i+1:i+1] = lines
230 i = i + len(parlay) + len(lines) + 1
233 def revert_separator(document):
234 " Revert separator insets to layout separators "
236 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
237 if document.textclass in beamer_classes:
238 beglaysep = "\\begin_layout Separator"
240 beglaysep = "\\begin_layout --Separator--"
242 parsep = [beglaysep, "", "\\end_layout", ""]
243 comert = ["\\begin_inset ERT", "status collapsed", "",
244 "\\begin_layout Plain Layout", "%", "\\end_layout",
245 "", "\\end_inset", ""]
246 empert = ["\\begin_inset ERT", "status collapsed", "",
247 "\\begin_layout Plain Layout", " ", "\\end_layout",
248 "", "\\end_inset", ""]
252 i = find_token(document.body, "\\begin_inset Separator", i)
256 lay = get_containing_layout(document.body, i)
258 document.warning("Malformed LyX document: Can't convert separator inset at line " + str(i))
265 kind = get_value(document.body, "\\begin_inset Separator", i, i+1, "plain").split()[1]
266 before = document.body[beg+1:i]
267 something_before = len(before) > 0 and len("".join(before)) > 0
268 j = find_end_of_inset(document.body, i)
269 after = document.body[j+1:end]
270 something_after = len(after) > 0 and len("".join(after)) > 0
272 beg = beg + len(before) + 1
273 elif something_before:
274 document.body[i:i] = ["\\end_layout", ""]
282 document.body[beg:j+1] = empert
285 document.body[beg:j+1] = comert
289 if layoutname == "Standard":
290 if not something_before:
291 document.body[beg:j+1] = parsep
293 document.body[i:i] = ["", "\\begin_layout Standard"]
296 document.body[beg:j+1] = ["\\begin_layout Standard"]
299 document.body[beg:j+1] = ["\\begin_deeper"]
301 end = end + 1 - (j + 1 - beg)
302 if not something_before:
303 document.body[i:i] = parsep
305 end = end + len(parsep)
306 document.body[i:i] = ["\\begin_layout Standard"]
307 document.body[end+2:end+2] = ["", "\\end_deeper", ""]
310 next_par_is_aligned = False
311 k = find_nonempty_line(document.body, end+1)
312 if k != -1 and check_token(document.body[k], "\\begin_layout"):
313 lay = get_containing_layout(document.body, k)
314 next_par_is_aligned = lay != False and \
315 find_token(document.body, "\\align", lay[1], lay[2]) != -1
316 if k != -1 and not next_par_is_aligned \
317 and not check_token(document.body[k], "\\end_deeper") \
318 and not check_token(document.body[k], "\\begin_deeper"):
319 if layoutname == "Standard":
320 document.body[beg:j+1] = [beglaysep]
323 document.body[beg:j+1] = ["\\begin_deeper", beglaysep]
324 end = end + 2 - (j + 1 - beg)
325 document.body[end+1:end+1] = ["", "\\end_deeper", ""]
329 del document.body[i:end+1]
331 del document.body[i:end-1]
336 def convert_parbreak(document):
338 Convert parbreak separators not specifically used to separate
339 environments to latexpar separators.
341 parbreakinset = "\\begin_inset Separator parbreak"
344 i = find_token(document.body, parbreakinset, i)
347 lay = get_containing_layout(document.body, i)
349 document.warning("Malformed LyX document: Can't convert separator inset at line " + str(i))
352 if lay[0] == "Standard":
353 # Convert only if not alone in the paragraph
354 k1 = find_nonempty_line(document.body, lay[1] + 1, i + 1)
355 k2 = find_nonempty_line(document.body, i + 1, lay[2])
356 if (k1 < i) or (k2 > i + 1) or not check_token(document.body[i], parbreakinset):
357 document.body[i] = document.body[i].replace("parbreak", "latexpar")
359 document.body[i] = document.body[i].replace("parbreak", "latexpar")
363 def revert_parbreak(document):
365 Revert latexpar separators to parbreak separators.
369 i = find_token(document.body, "\\begin_inset Separator latexpar", i)
372 document.body[i] = document.body[i].replace("latexpar", "parbreak")
376 def revert_smash(document):
377 " Set amsmath to on if smash commands are used "
379 commands = ["smash[t]", "smash[b]", "notag"]
380 i = find_token(document.header, "\\use_package amsmath", 0)
382 document.warning("Malformed LyX document: Can't find \\use_package amsmath.")
384 value = get_value(document.header, "\\use_package amsmath", i).split()[1]
386 # nothing to do if package is not auto but on or off
390 j = find_token(document.body, '\\begin_inset Formula', j)
393 k = find_end_of_inset(document.body, j)
395 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(j))
398 code = "\n".join(document.body[j:k])
400 if code.find("\\%s" % c) != -1:
401 # set amsmath to on, since it is loaded by the newer format
402 document.header[i] = "\\use_package amsmath 2"
407 def revert_swissgerman(document):
408 " Set language german-ch-old to german "
410 if document.language == "german-ch-old":
411 document.language = "german"
412 i = find_token(document.header, "\\language", 0)
414 document.header[i] = "\\language german"
417 j = find_token(document.body, "\\lang german-ch-old", j)
420 document.body[j] = document.body[j].replace("\\lang german-ch-old", "\\lang german")
424 def revert_use_package(document, pkg, commands, oldauto, supported):
425 # oldauto defines how the version we are reverting to behaves:
426 # if it is true, the old version uses the package automatically.
427 # if it is false, the old version never uses the package.
428 # If "supported" is true, the target version also supports this
430 regexp = re.compile(r'(\\use_package\s+%s)' % pkg)
431 p = find_re(document.header, regexp, 0)
432 value = "1" # default is auto
434 value = get_value(document.header, "\\use_package" , p).split()[1]
436 del document.header[p]
437 if value == "2" and not supported: # on
438 add_to_preamble(document, ["\\usepackage{" + pkg + "}"])
439 elif value == "1" and not oldauto: # auto
442 i = find_token(document.body, '\\begin_inset Formula', i)
445 j = find_end_of_inset(document.body, i)
447 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
450 code = "\n".join(document.body[i:j])
452 if code.find("\\%s" % c) != -1:
454 document.header[p] = "\\use_package " + pkg + " 2"
456 add_to_preamble(document, ["\\usepackage{" + pkg + "}"])
461 mathtools_commands = ["xhookrightarrow", "xhookleftarrow", "xRightarrow", \
462 "xrightharpoondown", "xrightharpoonup", "xrightleftharpoons", \
463 "xLeftarrow", "xleftharpoondown", "xleftharpoonup", \
464 "xleftrightarrow", "xLeftrightarrow", "xleftrightharpoons", \
467 def revert_xarrow(document):
468 "remove use_package mathtools"
469 revert_use_package(document, "mathtools", mathtools_commands, False, True)
472 def revert_beamer_lemma(document):
473 " Reverts beamer lemma layout to ERT "
475 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
476 if document.textclass not in beamer_classes:
482 i = find_token(document.body, "\\begin_layout Lemma", i)
485 j = find_end_of_layout(document.body, i)
487 document.warning("Malformed LyX document: Can't find end of Lemma layout")
490 arg1 = find_token(document.body, "\\begin_inset Argument 1", i, j)
491 endarg1 = find_end_of_inset(document.body, arg1)
492 arg2 = find_token(document.body, "\\begin_inset Argument 2", i, j)
493 endarg2 = find_end_of_inset(document.body, arg2)
497 beginPlain1 = find_token(document.body, "\\begin_layout Plain Layout", arg1, endarg1)
498 if beginPlain1 == -1:
499 document.warning("Malformed LyX document: Can't find arg1 plain Layout")
502 endPlain1 = find_end_of_inset(document.body, beginPlain1)
503 content1 = document.body[beginPlain1 + 1 : endPlain1 - 2]
504 subst1 = put_cmd_in_ert("<") + content1 + put_cmd_in_ert(">")
506 beginPlain2 = find_token(document.body, "\\begin_layout Plain Layout", arg2, endarg2)
507 if beginPlain2 == -1:
508 document.warning("Malformed LyX document: Can't find arg2 plain Layout")
511 endPlain2 = find_end_of_inset(document.body, beginPlain2)
512 content2 = document.body[beginPlain2 + 1 : endPlain2 - 2]
513 subst2 = put_cmd_in_ert("[") + content2 + put_cmd_in_ert("]")
517 del document.body[arg2 : endarg2 + 1]
519 del document.body[arg1 : endarg1 + 1]
521 del document.body[arg1 : endarg1 + 1]
523 del document.body[arg2 : endarg2 + 1]
525 # index of end layout has probably changed
526 j = find_end_of_layout(document.body, i)
528 document.warning("Malformed LyX document: Can't find end of Lemma layout")
534 # if this is not a consecutive env, add start command
536 begcmd = put_cmd_in_ert("\\begin{lemma}")
538 # has this a consecutive lemma?
539 consecutive = document.body[j + 2] == "\\begin_layout Lemma"
541 # if this is not followed by a consecutive env, add end command
543 document.body[j : j + 1] = put_cmd_in_ert("\\end{lemma}") + ["\\end_layout"]
545 document.body[i : i + 1] = ["\\begin_layout Standard", ""] + begcmd + subst1 + subst2
551 def revert_question_env(document):
553 Reverts question and question* environments of
554 theorems-ams-extended-bytype module to ERT
557 # Do we use theorems-ams-extended-bytype module?
558 if not "theorems-ams-extended-bytype" in document.get_module_list():
564 i = find_token(document.body, "\\begin_layout Question", i)
568 starred = document.body[i] == "\\begin_layout Question*"
570 j = find_end_of_layout(document.body, i)
572 document.warning("Malformed LyX document: Can't find end of Question layout")
576 # if this is not a consecutive env, add start command
580 begcmd = put_cmd_in_ert("\\begin{question*}")
582 begcmd = put_cmd_in_ert("\\begin{question}")
584 # has this a consecutive theorem of same type?
587 consecutive = document.body[j + 2] == "\\begin_layout Question*"
589 consecutive = document.body[j + 2] == "\\begin_layout Question"
591 # if this is not followed by a consecutive env, add end command
594 document.body[j : j + 1] = put_cmd_in_ert("\\end{question*}") + ["\\end_layout"]
596 document.body[j : j + 1] = put_cmd_in_ert("\\end{question}") + ["\\end_layout"]
598 document.body[i : i + 1] = ["\\begin_layout Standard", ""] + begcmd
600 add_to_preamble(document, "\\providecommand{\questionname}{Question}")
603 add_to_preamble(document, "\\theoremstyle{plain}\n" \
604 "\\newtheorem*{question*}{\\protect\\questionname}")
606 add_to_preamble(document, "\\theoremstyle{plain}\n" \
607 "\\newtheorem{question}{\\protect\\questionname}")
612 def convert_dashes(document):
613 "convert -- and --- to \\twohyphens and \\threehyphens"
615 if document.backend != "latex":
620 i = find_substring(document.body, "--", i+1)
623 line = document.body[i]
624 # skip label width string (bug 10243):
625 if line.startswith("\\labelwidthstring"):
627 # Do not touch hyphens in some insets:
629 value, start, end = get_containing_inset(document.body, i)
631 # False means no (or malformed) containing inset
632 value, start, end = "no inset", -1, -1
633 # We must not replace anything in insets that store LaTeX contents in .lyx files
634 # (math and command insets without overridden read() and write() methods.
635 # Filtering out IPA and ERT makes Text::readParToken() more simple,
636 # Flex Code is logical markup, typically rendered as typewriter
637 if (value.split()[0] in ["CommandInset", "ERT", "External", "Formula",
638 "FormulaMacro", "Graphics", "IPA", "listings"]
639 or value in ["Flex Code", "Flex URL"]):
643 layout, start, end, j = get_containing_layout(document.body, i)
644 except TypeError: # no (or malformed) containing layout
645 document.warning("Malformed LyX document: "
646 "Can't find layout at line %d" % i)
648 if layout == "LyX-Code":
651 # We can have an arbitrary number of consecutive hyphens.
652 # Replace as LaTeX does: First try emdash, then endash
653 line = line.replace("---", "\\threehyphens\n")
654 line = line.replace("--", "\\twohyphens\n")
655 document.body[i:i+1] = line.split('\n')
657 # remove ligature breaks between dashes
660 i = find_substring(document.body,
661 r"-\SpecialChar \textcompwordmark{}", i+1)
664 if document.body[i+1].startswith("-"):
665 document.body[i] = document.body[i].replace(
666 r"\SpecialChar \textcompwordmark{}", document.body.pop(i+1))
669 def revert_dashes(document):
671 Remove preamble code from 2.3->2.2 conversion.
672 Prevent ligatures of existing --- and --.
673 Revert \\twohyphens and \\threehyphens to -- and ---.
675 del_complete_lines(document.preamble,
676 ['% Added by lyx2lyx',
677 r'\renewcommand{\textendash}{--}',
678 r'\renewcommand{\textemdash}{---}'])
680 # Insert ligature breaks to prevent ligation of hyphens to dashes:
683 i = find_substring(document.body, "--", i+1)
686 line = document.body[i]
687 # skip label width string (bug 10243):
688 if line.startswith("\\labelwidthstring"):
690 # do not touch hyphens in some insets (cf. convert_dashes):
692 value, start, end = get_containing_inset(document.body, i)
694 # False means no (or malformed) containing inset
695 value, start, end = "no inset", -1, -1
696 if (value.split()[0] in ["CommandInset", "ERT", "External", "Formula",
697 "FormulaMacro", "Graphics", "IPA", "listings"]
698 or value == "Flex URL"):
701 line = line.replace("--", "-\\SpecialChar \\textcompwordmark{}\n-")
702 document.body[i:i+1] = line.split('\n')
704 # Revert \twohyphens and \threehyphens:
706 while i < len(document.body):
707 line = document.body[i]
708 if not line.endswith("hyphens"):
710 elif line.endswith("\\twohyphens") or line.endswith("\\threehyphens"):
711 line = line.replace("\\twohyphens", "--")
712 line = line.replace("\\threehyphens", "---")
713 document.body[i] = line + document.body.pop(i+1)
718 # order is important for the last three!
719 phrases = ["LyX", "LaTeX2e", "LaTeX", "TeX"]
721 def is_part_of_converted_phrase(line, j, phrase):
722 "is phrase part of an already converted phrase?"
724 converted = "\\SpecialCharNoPassThru \\" + p
725 pos = j + len(phrase) - len(converted)
727 if line[pos:pos+len(converted)] == converted:
732 def convert_phrases(document):
733 "convert special phrases from plain text to \\SpecialCharNoPassThru"
735 if document.backend != "latex":
739 while i < len(document.body):
740 if document.body[i] and document.body[i][0] == "\\":
741 words = document.body[i].split()
742 if len(words) > 1 and words[0] == "\\begin_inset" and \
743 words[1] in ["CommandInset", "External", "Formula", "Graphics", "listings"]:
744 # must not replace anything in insets that store LaTeX contents in .lyx files
745 # (math and command insets without overridden read() and write() methods)
746 j = find_end_of_inset(document.body, i)
748 document.warning("Malformed LyX document: Can't find end of inset at line %d" % (i))
755 for phrase in phrases:
756 j = document.body[i].find(phrase)
759 if not is_part_of_converted_phrase(document.body[i], j, phrase):
760 front = document.body[i][:j]
761 back = document.body[i][j+len(phrase):]
763 document.body.insert(i+1, back)
764 # We cannot use SpecialChar since we do not know whether we are outside passThru
765 document.body[i] = front + "\\SpecialCharNoPassThru \\" + phrase
769 def revert_phrases(document):
770 "revert special phrases to plain text"
773 while i < len(document.body):
774 words = document.body[i].split()
775 if len(words) > 1 and words[0] == "\\begin_inset" and \
776 words[1] in ["CommandInset", "External", "Formula", "Graphics", "listings"]:
777 # see convert_phrases
778 j = find_end_of_inset(document.body, i)
780 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
786 for phrase in phrases:
787 # we can replace SpecialChar since LyX ensures that it cannot be inserted into passThru parts
788 if document.body[i].find("\\SpecialChar \\" + phrase) >= 0:
789 document.body[i] = document.body[i].replace("\\SpecialChar \\" + phrase, phrase)
791 if document.body[i].find("\\SpecialCharNoPassThru \\" + phrase) >= 0:
792 document.body[i] = document.body[i].replace("\\SpecialCharNoPassThru \\" + phrase, phrase)
794 if replaced and i+1 < len(document.body) and \
795 (document.body[i+1].find("\\") != 0 or \
796 document.body[i+1].find("\\SpecialChar") == 0) and \
797 len(document.body[i]) + len(document.body[i+1]) <= 80:
798 document.body[i] = document.body[i] + document.body[i+1]
799 document.body[i+1:i+2] = []
804 def convert_specialchar_internal(document, forward):
805 specialchars = {"\\-":"softhyphen", "\\textcompwordmark{}":"ligaturebreak", \
806 "\\@.":"endofsentence", "\\ldots{}":"ldots", \
807 "\\menuseparator":"menuseparator", "\\slash{}":"breakableslash", \
808 "\\nobreakdash-":"nobreakdash", "\\LyX":"LyX", \
809 "\\TeX":"TeX", "\\LaTeX2e":"LaTeX2e", \
810 "\\LaTeX":"LaTeX" # must be after LaTeX2e
814 while i < len(document.body):
815 if document.body[i] and document.body[i][0] == "\\":
816 words = document.body[i].split()
817 if len(words) > 1 and words[0] == "\\begin_inset" and \
818 words[1] in ["CommandInset", "External", "Formula", "Graphics", "listings"]:
819 # see convert_phrases
820 j = find_end_of_inset(document.body, i)
822 document.warning("Malformed LyX document: Can't find end of %s inset at line %d" % (words[1], i))
828 if not "\\SpecialChar" in document.body[i]:
831 for key, value in specialchars.items():
833 document.body[i] = document.body[i].replace("\\SpecialChar " + key, "\\SpecialChar " + value)
834 document.body[i] = document.body[i].replace("\\SpecialCharNoPassThru " + key, "\\SpecialCharNoPassThru " + value)
836 document.body[i] = document.body[i].replace("\\SpecialChar " + value, "\\SpecialChar " + key)
837 document.body[i] = document.body[i].replace("\\SpecialCharNoPassThru " + value, "\\SpecialCharNoPassThru " + key)
841 def convert_specialchar(document):
842 "convert special characters to new syntax"
843 convert_specialchar_internal(document, True)
846 def revert_specialchar(document):
847 "convert special characters to old syntax"
848 convert_specialchar_internal(document, False)
851 def revert_georgian(document):
852 "Set the document language to English but assure Georgian output"
854 if document.language == "georgian":
855 document.language = "english"
856 i = find_token(document.header, "\\language georgian", 0)
858 document.header[i] = "\\language english"
859 j = find_token(document.header, "\\language_package default", 0)
861 document.header[j] = "\\language_package babel"
862 insert_document_option(document, "georgian")
865 def revert_sigplan_doi(document):
866 " Reverts sigplanconf DOI layout to ERT "
868 if document.textclass != "sigplanconf":
873 i = find_token(document.body, "\\begin_layout DOI", i)
876 j = find_end_of_layout(document.body, i)
878 document.warning("Malformed LyX document: Can't find end of DOI layout")
882 content = lyx2latex(document, document.body[i:j + 1])
883 add_to_preamble(document, ["\\doi{" + content + "}"])
884 del document.body[i:j + 1]
888 def revert_ex_itemargs(document):
889 " Reverts \\item arguments of the example environments (Linguistics module) to TeX-code "
891 if not "linguistics" in document.get_module_list():
895 example_layouts = ["Numbered Examples (consecutive)", "Subexample"]
897 i = find_token(document.body, "\\begin_inset Argument item:", i)
900 j = find_end_of_inset(document.body, i)
901 # Find containing paragraph layout
902 parent = get_containing_layout(document.body, i)
904 document.warning("Malformed LyX document: Can't find parent paragraph layout")
908 layoutname = parent[0]
909 if layoutname in example_layouts:
910 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
911 endPlain = find_end_of_layout(document.body, beginPlain)
912 content = document.body[beginPlain + 1 : endPlain]
913 del document.body[i:j+1]
914 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
915 document.body[parbeg : parbeg] = subst
919 def revert_forest(document):
920 " Reverts the forest environment (Linguistics module) to TeX-code "
922 if not "linguistics" in document.get_module_list():
927 i = find_token(document.body, "\\begin_inset Flex Structure Tree", i)
930 j = find_end_of_inset(document.body, i)
932 document.warning("Malformed LyX document: Can't find end of Structure Tree inset")
936 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
937 endPlain = find_end_of_layout(document.body, beginPlain)
938 content = lyx2latex(document, document.body[beginPlain : endPlain])
940 add_to_preamble(document, ["\\usepackage{forest}"])
942 document.body[i:j + 1] = put_cmd_in_ert("\\begin{forest}" + content + "\\end{forest}")
946 def revert_glossgroup(document):
947 " Reverts the GroupGlossedWords inset (Linguistics module) to TeX-code "
949 if not "linguistics" in document.get_module_list():
954 i = find_token(document.body, "\\begin_inset Flex GroupGlossedWords", i)
957 j = find_end_of_inset(document.body, i)
959 document.warning("Malformed LyX document: Can't find end of GroupGlossedWords inset")
963 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
964 endPlain = find_end_of_layout(document.body, beginPlain)
965 content = lyx2verbatim(document, document.body[beginPlain : endPlain])
967 document.body[i:j + 1] = ["{", "", content, "", "}"]
971 def revert_newgloss(document):
972 " Reverts the new Glosse insets (Linguistics module) to the old format "
974 if not "linguistics" in document.get_module_list():
977 glosses = ("\\begin_inset Flex Glosse", "\\begin_inset Flex Tri-Glosse")
978 for glosse in glosses:
981 i = find_token(document.body, glosse, i)
984 j = find_end_of_inset(document.body, i)
986 document.warning("Malformed LyX document: Can't find end of Glosse inset")
990 arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
991 endarg = find_end_of_inset(document.body, arg)
994 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
995 if argbeginPlain == -1:
996 document.warning("Malformed LyX document: Can't find arg plain Layout")
999 argendPlain = find_end_of_inset(document.body, argbeginPlain)
1000 argcontent = lyx2verbatim(document, document.body[argbeginPlain : argendPlain - 2])
1002 document.body[j:j] = ["", "\\begin_layout Plain Layout","\\backslash", "glt ",
1003 argcontent, "\\end_layout"]
1005 # remove Arg insets and paragraph, if it only contains this inset
1006 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
1007 del document.body[arg - 1 : endarg + 4]
1009 del document.body[arg : endarg + 1]
1011 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
1012 endPlain = find_end_of_layout(document.body, beginPlain)
1013 content = lyx2verbatim(document, document.body[beginPlain : endPlain])
1015 document.body[beginPlain + 1:endPlain] = [content]
1018 # Dissolve ERT insets
1019 for glosse in glosses:
1022 i = find_token(document.body, glosse, i)
1025 j = find_end_of_inset(document.body, i)
1027 document.warning("Malformed LyX document: Can't find end of Glosse inset")
1031 ert = find_token(document.body, "\\begin_inset ERT", i, j)
1034 ertend = find_end_of_inset(document.body, ert)
1036 document.warning("Malformed LyX document: Can't find end of ERT inset")
1039 ertcontent = get_ert(document.body, ert, True)
1040 document.body[ert : ertend + 1] = [ertcontent]
1044 def convert_newgloss(document):
1045 " Converts Glosse insets (Linguistics module) to the new format "
1047 if not "linguistics" in document.get_module_list():
1050 glosses = ("\\begin_inset Flex Glosse", "\\begin_inset Flex Tri-Glosse")
1051 for glosse in glosses:
1054 i = find_token(document.body, glosse, i)
1057 j = find_end_of_inset(document.body, i)
1059 document.warning("Malformed LyX document: Can't find end of Glosse inset")
1066 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", k, j)
1067 if beginPlain == -1:
1069 endPlain = find_end_of_layout(document.body, beginPlain)
1071 document.warning("Malformed LyX document: Can't find end of Glosse layout")
1075 glt = find_token(document.body, "\\backslash", beginPlain, endPlain)
1076 if glt != -1 and document.body[glt + 1].startswith("glt"):
1077 document.body[glt + 1] = document.body[glt + 1].lstrip("glt").lstrip()
1078 argcontent = document.body[glt + 1 : endPlain]
1079 document.body[beginPlain + 1 : endPlain] = ["\\begin_inset Argument 1", "status open", "",
1080 "\\begin_layout Plain Layout", "\\begin_inset ERT", "status open", "",
1081 "\\begin_layout Plain Layout", ""] + argcontent + ["\\end_layout", "", "\\end_inset", "",
1082 "\\end_layout", "", "\\end_inset"]
1084 content = document.body[beginPlain + 1 : endPlain]
1085 document.body[beginPlain + 1 : endPlain] = ["\\begin_inset ERT", "status open", "",
1086 "\\begin_layout Plain Layout"] + content + ["\\end_layout", "", "\\end_inset"]
1088 endPlain = find_end_of_layout(document.body, beginPlain)
1090 j = find_end_of_inset(document.body, i)
1095 def convert_BoxFeatures(document):
1096 " adds new box features "
1100 i = find_token(document.body, "height_special", i)
1103 document.body[i+1:i+1] = ['thickness "0.4pt"', 'separation "3pt"', 'shadowsize "4pt"']
1107 def revert_BoxFeatures(document):
1108 " outputs new box features as TeX code "
1112 defaultThick = "0.4pt"
1113 defaultShadow = "4pt"
1115 i = find_token(document.body, "thickness", i)
1118 binset = find_token(document.body, "\\begin_inset Box", i - 11)
1119 if binset == -1 or binset != i - 11:
1121 continue # then "thickness" is is just a word in the text
1122 einset = find_end_of_inset(document.body, binset)
1124 document.warning("Malformed LyX document: Can't find end of box inset!")
1127 # read out the values
1128 beg = document.body[i].find('"');
1129 end = document.body[i].rfind('"');
1130 thickness = document.body[i][beg+1:end];
1131 beg = document.body[i+1].find('"');
1132 end = document.body[i+1].rfind('"');
1133 separation = document.body[i+1][beg+1:end];
1134 beg = document.body[i+2].find('"');
1135 end = document.body[i+2].rfind('"');
1136 shadowsize = document.body[i+2][beg+1:end];
1138 # first output the closing brace
1139 if shadowsize != defaultShadow or separation != defaultSep or thickness != defaultThick:
1140 document.body[einset + 1 : einset + 1] = put_cmd_in_ert("}")
1141 # delete the specification
1142 del document.body[i:i+3]
1143 # we have now the problem that if there is already \(f)colorbox in ERT around the inset
1144 # the ERT from this routine must be around it
1145 regexp = re.compile(r'^.*colorbox{.*$')
1146 pos = find_re(document.body, regexp, binset - 4)
1147 if pos != -1 and pos == binset - 4:
1151 # now output the lengths
1152 if shadowsize != defaultShadow or separation != defaultSep or thickness != defaultThick:
1153 document.body[pos : pos] = put_cmd_in_ert("{")
1154 if thickness != defaultThick:
1155 document.body[pos + 5 : pos +6] = ["{\\backslash fboxrule " + thickness]
1156 if separation != defaultSep and thickness == defaultThick:
1157 document.body[pos + 5 : pos +6] = ["{\\backslash fboxsep " + separation]
1158 if separation != defaultSep and thickness != defaultThick:
1159 document.body[pos + 5 : pos +6] = ["{\\backslash fboxrule " + thickness + "\\backslash fboxsep " + separation]
1160 if shadowsize != defaultShadow and separation == defaultSep and thickness == defaultThick:
1161 document.body[pos + 5 : pos +6] = ["{\\backslash shadowsize " + shadowsize]
1162 if shadowsize != defaultShadow and separation != defaultSep and thickness == defaultThick:
1163 document.body[pos + 5 : pos +6] = ["{\\backslash fboxsep " + separation + "\\backslash shadowsize " + shadowsize]
1164 if shadowsize != defaultShadow and separation == defaultSep and thickness != defaultThick:
1165 document.body[pos + 5 : pos +6] = ["{\\backslash fboxrule " + thickness + "\\backslash shadowsize " + shadowsize]
1166 if shadowsize != defaultShadow and separation != defaultSep and thickness != defaultThick:
1167 document.body[pos + 5 : pos +6] = ["{\\backslash fboxrule " + thickness + "\\backslash fboxsep " + separation + "\\backslash shadowsize " + shadowsize]
1170 def convert_origin(document):
1171 " Insert the origin tag "
1173 i = find_token(document.header, "\\textclass ", 0)
1175 document.warning("Malformed LyX document: No \\textclass!!")
1177 if document.dir == u'':
1181 if document.systemlyxdir and document.systemlyxdir != u'':
1183 if os.path.isabs(document.dir):
1184 absdir = os.path.normpath(document.dir)
1186 absdir = os.path.normpath(os.path.abspath(document.dir))
1187 if os.path.isabs(document.systemlyxdir):
1188 abssys = os.path.normpath(document.systemlyxdir)
1190 abssys = os.path.normpath(os.path.abspath(document.systemlyxdir))
1191 relpath = os.path.relpath(absdir, abssys)
1192 if relpath.find(u'..') == 0:
1197 origin = document.dir.replace(u'\\', u'/') + u'/'
1199 origin = os.path.join(u"/systemlyxdir", relpath).replace(u'\\', u'/') + u'/'
1200 document.header[i:i] = ["\\origin " + origin]
1203 def revert_origin(document):
1204 " Remove the origin tag "
1206 i = find_token(document.header, "\\origin ", 0)
1208 document.warning("Malformed LyX document: No \\origin!!")
1210 del document.header[i]
1213 color_names = ["brown", "darkgray", "gray", \
1214 "lightgray", "lime", "olive", "orange", \
1215 "pink", "purple", "teal", "violet"]
1217 def revert_textcolor(document):
1218 " revert new \\textcolor colors to TeX code "
1224 i = find_token(document.body, "\\color ", i)
1228 for color in list(color_names):
1229 if document.body[i] == "\\color " + color:
1230 # register that xcolor must be loaded in the preamble
1233 add_to_preamble(document, ["\\@ifundefined{rangeHsb}{\\usepackage{xcolor}}{}"])
1234 # find the next \\color and/or the next \\end_layout
1235 j = find_token(document.body, "\\color", i + 1)
1236 k = find_token(document.body, "\\end_layout", i + 1)
1237 if j == -1 and k != -1:
1240 # first output the closing brace
1242 document.body[k: k] = put_cmd_in_ert("}")
1244 document.body[j: j] = put_cmd_in_ert("}")
1245 # now output the \textcolor command
1246 document.body[i : i + 1] = put_cmd_in_ert("\\textcolor{" + color + "}{")
1250 def convert_colorbox(document):
1251 "Add color settings for boxes."
1254 i = find_token(document.body, "shadowsize", i)
1257 # check whether this is really a LyX Box setting
1258 start, end = is_in_inset(document.body, i, "\\begin_inset Box")
1260 find_token(document.body, "\\begin_layout", start, i) != -1):
1263 document.body[i+1:i+1] = ['framecolor "black"',
1264 'backgroundcolor "none"']
1268 def revert_colorbox(document):
1269 """Change box color settings to LaTeX code."""
1273 i = find_token(document.body, "\\begin_inset Box", i)
1277 j = find_end_of_inset(document.body, i)
1278 k = find_token(document.body, "\\begin_layout", i, j)
1280 document.warning("Malformed LyX document: no layout in Box inset!")
1283 # Get and delete colour settings:
1284 framecolor = get_quoted_value(document.body, "framecolor", i, k, delete=True)
1285 backcolor = get_quoted_value(document.body, "backgroundcolor", i, k + 1, delete=True)
1286 if not framecolor or not backcolor:
1287 document.warning("Malformed LyX document: color options not found in Box inset!")
1290 if framecolor == "black" and backcolor == "none": # default values
1294 # Emulate non-default colours with LaTeX code:
1295 einset = find_end_of_inset(document.body, i)
1297 document.warning("Malformed LyX document: Can't find end of box inset!")
1300 add_to_preamble(document, ["\\@ifundefined{rangeHsb}{\\usepackage{xcolor}}{}"])
1301 # insert the closing brace first (keeps indices 'i' and 'einset' valid)
1302 document.body[einset+1:einset+1] = put_cmd_in_ert("}")
1303 # now insert the (f)color box command
1304 if ("Box Boxed" in document.body[i]): # framed box, use \fcolorbox
1305 # change the box type (frame added by \fcolorbox)
1306 document.body[i] = "\\begin_inset Box Frameless"
1307 # ensure an inner box:
1309 if not set_bool_value(document.body, "has_inner_box", True, i+3, i+4):
1310 set_bool_value(document.body, "use_makebox", True, i+6, i+7)
1312 document.warning("Malformed LyX document: 'has_inner_box' or "
1313 "'use_makebox' option not found in box inset!")
1314 ertinset = put_cmd_in_ert("\\fcolorbox{%s}{%s}{"% (framecolor, backcolor))
1316 ertinset = put_cmd_in_ert("\\colorbox{%s}{" % backcolor)
1317 document.body[i:i] = ertinset + [""]
1321 def revert_mathmulticol(document):
1322 " Convert formulas to ERT if they contain multicolumns "
1326 i = find_token(document.body, '\\begin_inset Formula', i)
1329 j = find_end_of_inset(document.body, i)
1331 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
1334 lines = document.body[i:j]
1335 lines[0] = lines[0].replace('\\begin_inset Formula', '').lstrip()
1336 code = "\n".join(lines)
1341 n = code.find("\\multicolumn", k)
1342 # no need to convert degenerated multicolumn cells,
1343 # they work in old LyX versions as "math ERT"
1344 if n != -1 and code.find("\\multicolumn{1}", k) != n:
1345 ert = put_cmd_in_ert(code)
1346 document.body[i:j+1] = ert
1352 i = find_end_of_inset(document.body, i)
1357 def revert_jss(document):
1358 " Reverts JSS In_Preamble commands to ERT in preamble "
1360 if document.textclass != "jss":
1369 # at first revert the inset layouts because they can be part of the In_Preamble layouts
1370 while m != -1 or j != -1 or h != -1 or k != -1 or n != -1:
1373 h = find_token(document.body, "\\begin_inset Flex Pkg", h)
1375 endh = find_end_of_inset(document.body, h)
1376 document.body[endh - 2 : endh + 1] = put_cmd_in_ert("}")
1377 document.body[h : h + 4] = put_cmd_in_ert("\\pkg{")
1381 m = find_token(document.body, "\\begin_inset Flex Proglang", m)
1383 endm = find_end_of_inset(document.body, m)
1384 document.body[endm - 2 : endm + 1] = put_cmd_in_ert("}")
1385 document.body[m : m + 4] = put_cmd_in_ert("\\proglang{")
1389 j = find_token(document.body, "\\begin_inset Flex Code", j)
1391 # assure that we are not in a Code Chunk inset
1392 if document.body[j][-1] == "e":
1393 endj = find_end_of_inset(document.body, j)
1394 document.body[endj - 2 : endj + 1] = put_cmd_in_ert("}")
1395 document.body[j : j + 4] = put_cmd_in_ert("\\code{")
1401 k = find_token(document.body, "\\begin_inset Flex E-mail", k)
1403 endk = find_end_of_inset(document.body, k)
1404 document.body[endk - 2 : endk + 1] = put_cmd_in_ert("}")
1405 document.body[k : k + 4] = put_cmd_in_ert("\\email{")
1409 n = find_token(document.body, "\\begin_inset Flex URL", n)
1411 endn = find_end_of_inset(document.body, n)
1412 document.body[endn - 2 : endn + 1] = put_cmd_in_ert("}")
1413 document.body[n : n + 4] = put_cmd_in_ert("\\url{")
1415 # now revert the In_Preamble layouts
1417 i = find_token(document.body, "\\begin_layout Title", 0)
1420 j = find_end_of_layout(document.body, i)
1422 document.warning("Malformed LyX document: Can't find end of Title layout")
1425 content = lyx2latex(document, document.body[i:j + 1])
1426 add_to_preamble(document, ["\\title{" + content + "}"])
1427 del document.body[i:j + 1]
1429 i = find_token(document.body, "\\begin_layout Author", 0)
1432 j = find_end_of_layout(document.body, i)
1434 document.warning("Malformed LyX document: Can't find end of Author layout")
1437 content = lyx2latex(document, document.body[i:j + 1])
1438 add_to_preamble(document, ["\\author{" + content + "}"])
1439 del document.body[i:j + 1]
1441 i = find_token(document.body, "\\begin_layout Plain Author", 0)
1444 j = find_end_of_layout(document.body, i)
1446 document.warning("Malformed LyX document: Can't find end of Plain Author layout")
1449 content = lyx2latex(document, document.body[i:j + 1])
1450 add_to_preamble(document, ["\\Plainauthor{" + content + "}"])
1451 del document.body[i:j + 1]
1453 i = find_token(document.body, "\\begin_layout Plain Title", 0)
1456 j = find_end_of_layout(document.body, i)
1458 document.warning("Malformed LyX document: Can't find end of Plain Title layout")
1461 content = lyx2latex(document, document.body[i:j + 1])
1462 add_to_preamble(document, ["\\Plaintitle{" + content + "}"])
1463 del document.body[i:j + 1]
1465 i = find_token(document.body, "\\begin_layout Short Title", 0)
1468 j = find_end_of_layout(document.body, i)
1470 document.warning("Malformed LyX document: Can't find end of Short Title layout")
1473 content = lyx2latex(document, document.body[i:j + 1])
1474 add_to_preamble(document, ["\\Shorttitle{" + content + "}"])
1475 del document.body[i:j + 1]
1477 i = find_token(document.body, "\\begin_layout Abstract", 0)
1480 j = find_end_of_layout(document.body, i)
1482 document.warning("Malformed LyX document: Can't find end of Abstract layout")
1485 content = lyx2latex(document, document.body[i:j + 1])
1486 add_to_preamble(document, ["\\Abstract{" + content + "}"])
1487 del document.body[i:j + 1]
1489 i = find_token(document.body, "\\begin_layout Keywords", 0)
1492 j = find_end_of_layout(document.body, i)
1494 document.warning("Malformed LyX document: Can't find end of Keywords layout")
1497 content = lyx2latex(document, document.body[i:j + 1])
1498 add_to_preamble(document, ["\\Keywords{" + content + "}"])
1499 del document.body[i:j + 1]
1501 i = find_token(document.body, "\\begin_layout Plain Keywords", 0)
1504 j = find_end_of_layout(document.body, i)
1506 document.warning("Malformed LyX document: Can't find end of Plain Keywords layout")
1509 content = lyx2latex(document, document.body[i:j + 1])
1510 add_to_preamble(document, ["\\Plainkeywords{" + content + "}"])
1511 del document.body[i:j + 1]
1513 i = find_token(document.body, "\\begin_layout Address", 0)
1516 j = find_end_of_layout(document.body, i)
1518 document.warning("Malformed LyX document: Can't find end of Address layout")
1521 content = lyx2latex(document, document.body[i:j + 1])
1522 add_to_preamble(document, ["\\Address{" + content + "}"])
1523 del document.body[i:j + 1]
1524 # finally handle the code layouts
1529 while m != -1 or j != -1 or h != -1 or k != -1:
1532 h = find_token(document.body, "\\begin_inset Flex Code Chunk", h)
1534 endh = find_end_of_inset(document.body, h)
1535 document.body[endh : endh + 1] = put_cmd_in_ert("\\end{CodeChunk}")
1536 document.body[h : h + 3] = put_cmd_in_ert("\\begin{CodeChunk}")
1537 document.body[h - 1 : h] = ["\\begin_layout Standard"]
1541 j = find_token(document.body, "\\begin_layout Code Input", j)
1543 endj = find_end_of_layout(document.body, j)
1544 document.body[endj : endj + 1] = ["\\end_layout", "", "\\begin_layout Standard"]
1545 document.body[endj + 3 : endj + 4] = put_cmd_in_ert("\\end{CodeInput}")
1546 document.body[endj + 13 : endj + 13] = ["\\end_layout", "", "\\begin_layout Standard"]
1547 document.body[j + 1 : j] = ["\\end_layout", "", "\\begin_layout Standard"]
1548 document.body[j : j + 1] = put_cmd_in_ert("\\begin{CodeInput}")
1552 k = find_token(document.body, "\\begin_layout Code Output", k)
1554 endk = find_end_of_layout(document.body, k)
1555 document.body[endk : endk + 1] = ["\\end_layout", "", "\\begin_layout Standard"]
1556 document.body[endk + 3 : endk + 4] = put_cmd_in_ert("\\end{CodeOutput}")
1557 document.body[endk + 13 : endk + 13] = ["\\end_layout", "", "\\begin_layout Standard"]
1558 document.body[k + 1 : k] = ["\\end_layout", "", "\\begin_layout Standard"]
1559 document.body[k : k + 1] = put_cmd_in_ert("\\begin{CodeOutput}")
1563 m = find_token(document.body, "\\begin_layout Code", m)
1565 endm = find_end_of_layout(document.body, m)
1566 document.body[endm : endm + 1] = ["\\end_layout", "", "\\begin_layout Standard"]
1567 document.body[endm + 3 : endm + 4] = put_cmd_in_ert("\\end{Code}")
1568 document.body[endm + 13 : endm + 13] = ["\\end_layout", "", "\\begin_layout Standard"]
1569 document.body[m + 1 : m] = ["\\end_layout", "", "\\begin_layout Standard"]
1570 document.body[m : m + 1] = put_cmd_in_ert("\\begin{Code}")
1574 def convert_subref(document):
1575 " converts sub: ref prefixes to subref: "
1578 rx = re.compile(r'^name \"sub:(.+)$')
1581 i = find_token(document.body, "\\begin_inset CommandInset label", i)
1584 j = find_end_of_inset(document.body, i)
1586 document.warning("Malformed LyX document: Can't find end of Label inset at line " + str(i))
1590 for p in range(i, j):
1591 m = rx.match(document.body[p])
1594 document.body[p] = "name \"subsec:" + label
1598 rx = re.compile(r'^reference \"sub:(.+)$')
1601 i = find_token(document.body, "\\begin_inset CommandInset ref", i)
1604 j = find_end_of_inset(document.body, i)
1606 document.warning("Malformed LyX document: Can't find end of Ref inset at line " + str(i))
1610 for p in range(i, j):
1611 m = rx.match(document.body[p])
1614 document.body[p] = "reference \"subsec:" + label
1620 def revert_subref(document):
1621 " reverts subref: ref prefixes to sub: "
1624 rx = re.compile(r'^name \"subsec:(.+)$')
1627 i = find_token(document.body, "\\begin_inset CommandInset label", i)
1630 j = find_end_of_inset(document.body, i)
1632 document.warning("Malformed LyX document: Can't find end of Label inset at line " + str(i))
1636 for p in range(i, j):
1637 m = rx.match(document.body[p])
1640 document.body[p] = "name \"sub:" + label
1645 rx = re.compile(r'^reference \"subsec:(.+)$')
1648 i = find_token(document.body, "\\begin_inset CommandInset ref", i)
1651 j = find_end_of_inset(document.body, i)
1653 document.warning("Malformed LyX document: Can't find end of Ref inset at line " + str(i))
1657 for p in range(i, j):
1658 m = rx.match(document.body[p])
1661 document.body[p] = "reference \"sub:" + label
1666 def convert_nounzip(document):
1667 " remove the noUnzip parameter of graphics insets "
1669 rx = re.compile(r'\s*noUnzip\s*$')
1672 i = find_token(document.body, "\\begin_inset Graphics", i)
1675 j = find_end_of_inset(document.body, i)
1677 document.warning("Malformed LyX document: Can't find end of graphics inset at line " + str(i))
1681 k = find_re(document.body, rx, i, j)
1683 del document.body[k]
1688 def convert_revert_external_bbox(document, forward):
1689 " add units to bounding box of external insets "
1691 rx = re.compile(r'^\s*boundingBox\s+\S+\s+\S+\s+\S+\s+\S+\s*$')
1694 i = find_token(document.body, "\\begin_inset External", i)
1697 j = find_end_of_inset(document.body, i)
1699 document.warning("Malformed LyX document: Can't find end of external inset at line " + str(i))
1702 k = find_re(document.body, rx, i, j)
1706 tokens = document.body[k].split()
1708 for t in range(1, 5):
1711 for t in range(1, 5):
1712 tokens[t] = length_in_bp(tokens[t])
1713 document.body[k] = "\tboundingBox " + tokens[1] + " " + tokens[2] + " " + \
1714 tokens[3] + " " + tokens[4]
1718 def convert_external_bbox(document):
1719 convert_revert_external_bbox(document, True)
1722 def revert_external_bbox(document):
1723 convert_revert_external_bbox(document, False)
1726 def revert_tcolorbox_1(document):
1727 " Reverts the Flex:Subtitle inset of tcolorbox to TeX-code "
1729 i = find_token(document.header, "tcolorbox", 0)
1736 flex = find_token(document.body, "\\begin_inset Flex Subtitle", flex)
1740 flexEnd = find_end_of_inset(document.body, flex)
1742 document.warning("Malformed LyX document! No end of Flex Subtitle found.")
1746 wasOpt = revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, False, True, False)
1747 flexEnd = find_end_of_inset(document.body, flex)
1749 document.warning("Malformed LyX document! No end of Flex Subtitle found.")
1752 revert_Argument_to_TeX_brace(document, flex, flexEnd, 2, 2, False, False, False)
1753 flexEnd = find_end_of_inset(document.body, flex)
1755 document.warning("Malformed LyX document! No end of Flex Subtitle found.")
1759 bp = find_token(document.body, "\\begin_layout Plain Layout", flex)
1761 document.warning("Malformed LyX document! No Flex Subtitle layout found.")
1765 ep = find_end_of_layout(document.body, bp)
1767 document.warning("Malformed LyX document! No end of layout found.")
1771 document.body[ep : flexEnd + 1] = put_cmd_in_ert("}")
1773 document.body[flex : bp + 1] = put_cmd_in_ert("\\tcbsubtitle")
1775 document.body[flex : bp + 1] = put_cmd_in_ert("\\tcbsubtitle{")
1779 def revert_tcolorbox_2(document):
1780 " Reverts the Flex:Raster_Color_Box inset of tcolorbox to TeX-code "
1782 i = find_token(document.header, "tcolorbox", 0)
1788 flex = find_token(document.body, "\\begin_inset Flex Raster Color Box", flex)
1792 flexEnd = find_end_of_inset(document.body, flex)
1794 document.warning("Malformed LyX document! No end of Flex Raster Color Box found.")
1798 revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, True, True, False)
1800 bp = find_token(document.body, "\\begin_layout Plain Layout", flex)
1802 document.warning("Malformed LyX document! No plain layout in Raster Color Box found.")
1806 ep = find_end_of_layout(document.body, bp)
1808 document.warning("Malformed LyX document! No end of layout found.")
1812 flexEnd = find_end_of_inset(document.body, flex)
1814 document.warning("Malformed LyX document! No end of Flex Raster Color Box found.")
1817 document.body[ep : flexEnd + 1] = put_cmd_in_ert("\\end{tcbraster}")
1818 document.body[flex : bp + 1] = put_cmd_in_ert("\\begin{tcbraster}")
1822 def revert_tcolorbox_3(document):
1823 " Reverts the Flex:Custom_Color_Box_1 inset of tcolorbox to TeX-code "
1825 i = find_token(document.header, "tcolorbox", 0)
1831 flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 1", flex)
1835 flexEnd = find_end_of_inset(document.body, flex)
1837 document.warning("Malformed LyX document! No end of Flex Custom Color Box 1 found.")
1841 revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, True, True, False)
1842 flexEnd = find_end_of_inset(document.body, flex)
1844 document.warning("Malformed LyX document! No end of Flex Subtitle found.")
1847 revert_Argument_to_TeX_brace(document, flex, flexEnd, 2, 2, True, False, False)
1849 bp = find_token(document.body, "\\begin_layout Plain Layout", flex)
1851 document.warning("Malformed LyX document! No plain layout in Custom Color Box 1 found.")
1855 ep = find_end_of_layout(document.body, bp)
1857 document.warning("Malformed LyX document! No end of layout found.")
1861 flexEnd = find_end_of_inset(document.body, flex)
1863 document.warning("Malformed LyX document! No end of Flex Custom Color Box 1 found.")
1867 document.body[ep : flexEnd + 1] = put_cmd_in_ert("{}\\end{cBoxA}")
1868 document.body[flex : bp + 1] = put_cmd_in_ert("\\begin{cBoxA}")
1872 def revert_tcolorbox_4(document):
1873 " Reverts the Flex:Custom_Color_Box_2 inset of tcolorbox to TeX-code "
1875 i = find_token(document.header, "tcolorbox", 0)
1881 flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 2", flex)
1885 flexEnd = find_end_of_inset(document.body, flex)
1887 document.warning("Malformed LyX document! No end of Flex Custom Color Box 2 found.")
1891 revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, True, True, False)
1892 flexEnd = find_end_of_inset(document.body, flex)
1894 document.warning("Malformed LyX document! No end of Flex Subtitle found.")
1897 revert_Argument_to_TeX_brace(document, flex, flexEnd, 2, 2, True, False, False)
1898 flexEnd = find_end_of_inset(document.body, flex)
1900 document.warning("Malformed LyX document! No end of Flex Custom Color Box 2 found.")
1904 bp = find_token(document.body, "\\begin_layout Plain Layout", flex)
1906 document.warning("Malformed LyX document! No plain layout in Custom Color Box 2 found.")
1910 ep = find_end_of_layout(document.body, bp)
1912 document.warning("Malformed LyX document! No end of layout found.")
1916 document.body[ep : flexEnd + 1] = put_cmd_in_ert("{}\\end{cBoxB}")
1917 document.body[flex : bp + 1] = put_cmd_in_ert("\\begin{cBoxB}")
1921 def revert_tcolorbox_5(document):
1922 " Reverts the Flex:Custom_Color_Box_3 inset of tcolorbox to TeX-code "
1924 i = find_token(document.header, "tcolorbox", 0)
1930 flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 3", flex)
1934 flexEnd = find_end_of_inset(document.body, flex)
1936 document.warning("Malformed LyX document! No end of Flex Custom Color Box 3 found.")
1940 revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, True, True, False)
1941 flexEnd = find_end_of_inset(document.body, flex)
1943 document.warning("Malformed LyX document! No end of Flex Subtitle found.")
1946 revert_Argument_to_TeX_brace(document, flex, flexEnd, 2, 2, True, False, False)
1947 flexEnd = find_end_of_inset(document.body, flex)
1949 document.warning("Malformed LyX document! No end of Flex Custom Color Box 3 found.")
1953 bp = find_token(document.body, "\\begin_layout Plain Layout", flex)
1955 document.warning("Malformed LyX document! No plain layout in Custom Color Box 3 found.")
1959 ep = find_end_of_layout(document.body, bp)
1961 document.warning("Malformed LyX document! No end of layout found.")
1965 document.body[ep : flexEnd + 1] = put_cmd_in_ert("{}\\end{cBoxC}")
1966 document.body[flex : bp + 1] = put_cmd_in_ert("\\begin{cBoxC}")
1970 def revert_tcolorbox_6(document):
1971 " Reverts the Flex:Custom_Color_Box_4 inset of tcolorbox to TeX-code "
1973 i = find_token(document.header, "tcolorbox", 0)
1979 flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 4", flex)
1983 flexEnd = find_end_of_inset(document.body, flex)
1985 document.warning("Malformed LyX document! No end of Flex Custom Color Box 4 found.")
1989 revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, True, True, False)
1990 flexEnd = find_end_of_inset(document.body, flex)
1992 document.warning("Malformed LyX document! No end of Flex Subtitle found.")
1995 revert_Argument_to_TeX_brace(document, flex, flexEnd, 2, 2, True, False, False)
1996 flexEnd = find_end_of_inset(document.body, flex)
1998 document.warning("Malformed LyX document! No end of Flex Custom Color Box 4 found.")
2002 bp = find_token(document.body, "\\begin_layout Plain Layout", flex)
2004 document.warning("Malformed LyX document! No plain layout in Custom Color Box 4 found.")
2008 ep = find_end_of_layout(document.body, bp)
2010 document.warning("Malformed LyX document! No end of layout found.")
2014 document.body[ep : flexEnd + 1] = put_cmd_in_ert("{}\\end{cBoxD}")
2015 document.body[flex : bp + 1] = put_cmd_in_ert("\\begin{cBoxD}")
2019 def revert_tcolorbox_7(document):
2020 " Reverts the Flex:Custom_Color_Box_5 inset of tcolorbox to TeX-code "
2022 i = find_token(document.header, "tcolorbox", 0)
2028 flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 5", flex)
2032 flexEnd = find_end_of_inset(document.body, flex)
2034 document.warning("Malformed LyX document! No end of Flex Custom Color Box 5 found.")
2038 revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, True, True, False)
2039 flexEnd = find_end_of_inset(document.body, flex)
2041 document.warning("Malformed LyX document! No end of Flex Subtitle found.")
2044 revert_Argument_to_TeX_brace(document, flex, flexEnd, 2, 2, True, False, False)
2045 flexEnd = find_end_of_inset(document.body, flex)
2047 document.warning("Malformed LyX document! No end of Flex Custom Color Box 5 found.")
2051 bp = find_token(document.body, "\\begin_layout Plain Layout", flex)
2053 document.warning("Malformed LyX document! No plain layout in Custom Color Box 5 found.")
2057 ep = find_end_of_layout(document.body, bp)
2059 document.warning("Malformed LyX document! No end of layout found.")
2063 document.body[ep : flexEnd + 1] = put_cmd_in_ert("{}\\end{cBoxE}")
2064 document.body[flex : bp + 1] = put_cmd_in_ert("\\begin{cBoxE}")
2068 def revert_tcolorbox_8(document):
2069 " Reverts the layout New Color Box Type of tcolorbox to TeX-code "
2073 i = find_token(document.body, "\\begin_layout New Color Box Type", i)
2077 j = find_end_of_layout(document.body, i)
2079 document.warning("Malformed LyX document! No end of New Color Box Type layout found.")
2083 wasOpt = revert_Argument_to_TeX_brace(document, i, j, 1, 1, False, True, True)
2084 j = find_end_of_layout(document.body, i)
2086 document.warning("Malformed LyX document! No end of New Color Box Type layout found.")
2089 revert_Argument_to_TeX_brace(document, i, j, 2, 2, False, False, True)
2090 j = find_end_of_layout(document.body, i)
2092 document.warning("Malformed LyX document! No end of New Color Box Type layout found.")
2095 revert_Argument_to_TeX_brace(document, i, j, 3, 4, False, True, False)
2096 j = find_end_of_layout(document.body, i)
2098 document.warning("Malformed LyX document! No end of New Color Box Type layout found.")
2101 document.body[i] = document.body[i].replace("\\begin_layout New Color Box Type", "\\begin_layout Standard")
2102 document.body[i + 1 : i + 1] = put_cmd_in_ert("\\newtcolorbox")
2103 k = find_end_of_inset(document.body, j)
2104 document.body[k + 2 : j + 2] = put_cmd_in_ert("{") + ["\\begin_inset ERT", "status collapsed", "\\begin_layout Plain Layout"]
2105 j = find_token(document.body, "\\begin_layout Standard", j + 1)
2106 document.body[j - 2 : j - 2] = ["\\end_layout", "\\end_inset"] + put_cmd_in_ert("}")
2110 def revert_moderncv_1(document):
2111 " Reverts the new inset of moderncv to TeX-code in preamble "
2113 if document.textclass != "moderncv":
2119 # at first revert the new styles
2121 i = find_token(document.body, "\\begin_layout CVIcons", 0)
2124 j = find_end_of_layout(document.body, i)
2126 document.warning("Malformed LyX document: Can't find end of CVIcons layout")
2129 content = lyx2latex(document, document.body[i:j + 1])
2130 add_to_preamble(document, ["\\moderncvicons{" + content + "}"])
2131 del document.body[i:j + 1]
2133 i = find_token(document.body, "\\begin_layout CVColumnWidth", 0)
2136 j = find_end_of_layout(document.body, i)
2138 document.warning("Malformed LyX document: Can't find end of CVColumnWidth layout")
2141 content = lyx2latex(document, document.body[i:j + 1])
2142 add_to_preamble(document, ["\\setlength{\hintscolumnwidth}{" + content + "}"])
2143 del document.body[i:j + 1]
2144 # now change the new styles to the obsolete ones
2146 i = find_token(document.body, "\\begin_layout Name", 0)
2149 j = find_end_of_layout(document.body, i)
2151 document.warning("Malformed LyX document: Can't find end of Name layout")
2154 lineArg = find_token(document.body, "\\begin_inset Argument 1", i)
2155 if lineArg > j and j != 0:
2158 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
2159 # we have to assure that no other inset is in the Argument
2160 beginInset = find_token(document.body, "\\begin_inset", beginPlain)
2161 endInset = find_token(document.body, "\\end_inset", beginPlain)
2164 while beginInset < endInset and beginInset != -1:
2165 beginInset = find_token(document.body, "\\begin_inset", k)
2166 endInset = find_token(document.body, "\\end_inset", l)
2169 Arg2 = document.body[l + 5 : l + 6]
2171 document.body[i : i + 1]= ["\\begin_layout FirstName"]
2172 # delete the Argument inset
2173 del( document.body[endInset - 2 : endInset + 3])
2174 del( document.body[lineArg : beginPlain + 1])
2175 document.body[i + 4 : i + 4]= ["\\begin_layout FamilyName"] + Arg2 + ["\\end_layout"] + [""]
2178 def revert_moderncv_2(document):
2179 " Reverts the phone inset of moderncv to the obsoleted mobile or fax "
2181 if document.textclass != "moderncv":
2188 i = find_token(document.body, "\\begin_layout Phone", i)
2191 j = find_end_of_layout(document.body, i)
2193 document.warning("Malformed LyX document: Can't find end of Phone layout")
2196 lineArg = find_token(document.body, "\\begin_inset Argument 1", i)
2197 if lineArg > j and j != 0:
2201 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
2202 # we have to assure that no other inset is in the Argument
2203 beginInset = find_token(document.body, "\\begin_inset", beginPlain)
2204 endInset = find_token(document.body, "\\end_inset", beginPlain)
2207 while beginInset < endInset and beginInset != -1:
2208 beginInset = find_token(document.body, "\\begin_inset", k)
2209 endInset = find_token(document.body, "\\end_inset", l)
2212 Arg = document.body[beginPlain + 1 : beginPlain + 2]
2214 if Arg[0] == "mobile":
2215 document.body[i : i + 1]= ["\\begin_layout Mobile"]
2217 document.body[i : i + 1]= ["\\begin_layout Fax"]
2218 # delete the Argument inset
2219 del(document.body[endInset - 2 : endInset + 1])
2220 del(document.body[lineArg : beginPlain + 3])
2224 def convert_moderncv_phone(document):
2225 " Convert the Fax and Mobile inset of moderncv to the new phone inset "
2227 if document.textclass != "moderncv":
2234 "Mobile" : "mobile",
2238 rx = re.compile(r'^\\begin_layout (\S+)$')
2240 # substitute \fax and \mobile by \phone[fax] and \phone[mobile], respectively
2241 i = find_token(document.body, "\\begin_layout", i)
2245 m = rx.match(document.body[i])
2249 if val not in list(phone_dict.keys()):
2252 j = find_end_of_layout(document.body, i)
2254 document.warning("Malformed LyX document: Can't find end of Mobile layout")
2258 document.body[i : i + 1] = ["\\begin_layout Phone", "\\begin_inset Argument 1", "status open", "",
2259 "\\begin_layout Plain Layout", phone_dict[val], "\\end_layout", "",
2263 def convert_moderncv_name(document):
2264 " Convert the FirstName and LastName layout of moderncv to the general Name layout "
2266 if document.textclass != "moderncv":
2269 fnb = 0 # Begin of FirstName inset
2270 fne = 0 # End of FirstName inset
2271 lnb = 0 # Begin of LastName (FamilyName) inset
2272 lne = 0 # End of LastName (FamilyName) inset
2273 nb = 0 # Begin of substituting Name inset
2274 ne = 0 # End of substituting Name inset
2275 FirstName = [] # FirstName content
2276 FamilyName = [] # LastName content
2280 fnb = find_token(document.body, "\\begin_layout FirstName", fnb)
2282 fne = find_end_of_layout(document.body, fnb)
2284 document.warning("Malformed LyX document: Can't find end of FirstName layout")
2286 FirstName = document.body[fnb + 1 : fne]
2288 lnb = find_token(document.body, "\\begin_layout FamilyName", lnb)
2290 lne = find_end_of_layout(document.body, lnb)
2292 document.warning("Malformed LyX document: Can't find end of FamilyName layout")
2294 FamilyName = document.body[lnb + 1 : lne]
2295 # Determine the region for the substituting Name layout
2296 if fnb == -1 and lnb == -1: # Neither FirstName nor FamilyName exists -> Do nothing
2298 elif fnb == -1: # Only FamilyName exists -> New Name insets replaces that
2301 elif lnb == -1: # Only FirstName exists -> New Name insets replaces that
2304 elif fne > lne: # FirstName position before FamilyName -> New Name insets spans
2305 nb = lnb # from FamilyName begin
2306 ne = fne # to FirstName end
2307 else: # FirstName position before FamilyName -> New Name insets spans
2308 nb = fnb # from FirstName begin
2309 ne = lne # to FamilyName end
2311 # Insert the substituting layout now. If FirstName exists, use an otpional argument.
2313 document.body[nb : ne + 1] = ["\\begin_layout Name"] + FamilyName + ["\\end_layout", ""]
2315 document.body[nb : ne + 1] = ["\\begin_layout Name", "\\begin_inset Argument 1", "status open", "",
2316 "\\begin_layout Plain Layout"] + FirstName + ["\\end_layout", "",
2317 "\\end_inset", ""] + FamilyName + ["\\end_layout", ""]
2320 def revert_achemso(document):
2321 " Reverts the flex inset Latin to TeX code "
2323 if document.textclass != "achemso":
2328 i = find_token(document.body, "\\begin_inset Flex Latin", i)
2330 j = find_end_of_inset(document.body, i)
2334 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2335 endPlain = find_end_of_layout(document.body, beginPlain)
2336 content = lyx2latex(document, document.body[beginPlain : endPlain])
2337 document.body[i:j + 1] = put_cmd_in_ert("\\latin{" + content + "}")
2339 document.warning("Malformed LyX document: Can't find end of flex inset Latin")
2344 fontsettings = ["\\font_roman", "\\font_sans", "\\font_typewriter", "\\font_math", \
2345 "\\font_sf_scale", "\\font_tt_scale"]
2346 fontdefaults = ["default", "default", "default", "auto", "100", "100"]
2347 fontquotes = [True, True, True, True, False, False]
2349 def convert_fontsettings(document):
2350 " Duplicate font settings "
2352 i = find_token(document.header, "\\use_non_tex_fonts ", 0)
2354 document.warning("Malformed LyX document: No \\use_non_tex_fonts!")
2355 use_non_tex_fonts = "false"
2357 use_non_tex_fonts = get_value(document.header, "\\use_non_tex_fonts", i)
2359 for f in fontsettings:
2360 i = find_token(document.header, f + " ", 0)
2362 document.warning("Malformed LyX document: No " + f + "!")
2364 # note that with i = -1, this will insert at the end
2366 value = fontdefaults[j]
2368 value = document.header[i][len(f):].strip()
2370 if use_non_tex_fonts == "true":
2371 document.header[i:i+1] = [f + ' "' + fontdefaults[j] + '" "' + value + '"']
2373 document.header[i:i+1] = [f + ' "' + value + '" "' + fontdefaults[j] + '"']
2375 if use_non_tex_fonts == "true":
2376 document.header[i:i+1] = [f + ' ' + fontdefaults[j] + ' ' + value]
2378 document.header[i:i+1] = [f + ' ' + value + ' ' + fontdefaults[j]]
2382 def revert_fontsettings(document):
2383 " Merge font settings "
2385 i = find_token(document.header, "\\use_non_tex_fonts ", 0)
2387 document.warning("Malformed LyX document: No \\use_non_tex_fonts!")
2388 use_non_tex_fonts = "false"
2390 use_non_tex_fonts = get_value(document.header, "\\use_non_tex_fonts", i)
2392 for f in fontsettings:
2393 i = find_token(document.header, f + " ", 0)
2395 document.warning("Malformed LyX document: No " + f + "!")
2398 line = get_value(document.header, f, i)
2401 q2 = line.find('"', q1+1)
2402 q3 = line.find('"', q2+1)
2403 q4 = line.find('"', q3+1)
2404 if q1 == -1 or q2 == -1 or q3 == -1 or q4 == -1:
2405 document.warning("Malformed LyX document: Missing quotes!")
2408 if use_non_tex_fonts == "true":
2409 document.header[i:i+1] = [f + ' ' + line[q3+1:q4]]
2411 document.header[i:i+1] = [f + ' ' + line[q1+1:q2]]
2413 if use_non_tex_fonts == "true":
2414 document.header[i:i+1] = [f + ' ' + line.split()[1]]
2416 document.header[i:i+1] = [f + ' ' + line.split()[0]]
2420 def revert_solution(document):
2421 " Reverts the solution environment of the theorem module to TeX code "
2423 # Do we use one of the modules that provides Solution?
2425 mods = document.get_module_list()
2427 if mod == "theorems-std" or mod == "theorems-bytype" \
2428 or mod == "theorems-ams" or mod == "theorems-ams-bytype":
2438 i = find_token(document.body, "\\begin_layout Solution", i)
2442 is_starred = document.body[i].startswith("\\begin_layout Solution*")
2443 if is_starred == True:
2445 LyXName = "Solution*"
2446 theoremName = "newtheorem*"
2449 LyXName = "Solution"
2450 theoremName = "newtheorem"
2452 j = find_end_of_layout(document.body, i)
2454 document.warning("Malformed LyX document: Can't find end of " + LyXName + " layout")
2458 # if this is not a consecutive env, add start command
2461 begcmd = put_cmd_in_ert("\\begin{%s}" % (LaTeXName))
2463 # has this a consecutive theorem of same type?
2464 consecutive = document.body[j + 2] == "\\begin_layout " + LyXName
2466 # if this is not followed by a consecutive env, add end command
2468 document.body[j : j + 1] = put_cmd_in_ert("\\end{%s}" % (LaTeXName)) + ["\\end_layout"]
2470 document.body[i : i + 1] = ["\\begin_layout Standard", ""] + begcmd
2472 add_to_preamble(document, "\\theoremstyle{definition}")
2473 if is_starred or mod == "theorems-bytype" or mod == "theorems-ams-bytype":
2474 add_to_preamble(document, "\\%s{%s}{\\protect\\solutionname}" % \
2475 (theoremName, LaTeXName))
2476 else: # mod == "theorems-std" or mod == "theorems-ams" and not is_starred
2477 add_to_preamble(document, "\\%s{%s}[thm]{\\protect\\solutionname}" % \
2478 (theoremName, LaTeXName))
2480 add_to_preamble(document, "\\providecommand{\solutionname}{Solution}")
2484 def revert_verbatim_star(document):
2485 from lyx_2_1 import revert_verbatim
2486 revert_verbatim(document, True)
2489 def convert_save_props(document):
2490 " Add save_transient_properties parameter. "
2491 i = find_token(document.header, '\\begin_header', 0)
2493 document.warning("Malformed lyx document: Missing '\\begin_header'.")
2495 document.header.insert(i + 1, '\\save_transient_properties true')
2498 def revert_save_props(document):
2499 " Remove save_transient_properties parameter. "
2500 i = find_token(document.header, "\\save_transient_properties", 0)
2503 del document.header[i]
2506 def convert_info_tabular_feature(document):
2508 return arg.replace("inset-modify tabular", "tabular-feature")
2509 convert_info_insets(document, "shortcut(s)?|icon", f)
2512 def revert_info_tabular_feature(document):
2514 return arg.replace("tabular-feature", "inset-modify tabular")
2515 convert_info_insets(document, "shortcut(s)?|icon", f)
2522 supported_versions = ["2.2.0", "2.2"]
2524 [475, [convert_separator]],
2525 # nothing to do for 476: We consider it a bug that older versions
2526 # did not load amsmath automatically for these commands, and do not
2527 # want to hardcode amsmath off.
2533 [481, [convert_dashes]],
2534 [482, [convert_phrases]],
2535 [483, [convert_specialchar]],
2540 [488, [convert_newgloss]],
2541 [489, [convert_BoxFeatures]],
2542 [490, [convert_origin]],
2544 [492, [convert_colorbox]],
2547 [495, [convert_subref]],
2548 [496, [convert_nounzip]],
2549 [497, [convert_external_bbox]],
2551 [499, [convert_moderncv_phone, convert_moderncv_name]],
2553 [501, [convert_fontsettings]],
2556 [504, [convert_save_props]],
2558 [506, [convert_info_tabular_feature]],
2559 [507, [convert_longtable_label]],
2560 [508, [convert_parbreak]]
2564 [507, [revert_parbreak]],
2565 [506, [revert_longtable_label]],
2566 [505, [revert_info_tabular_feature]],
2568 [503, [revert_save_props]],
2569 [502, [revert_verbatim_star]],
2570 [501, [revert_solution]],
2571 [500, [revert_fontsettings]],
2572 [499, [revert_achemso]],
2573 [498, [revert_moderncv_1, revert_moderncv_2]],
2574 [497, [revert_tcolorbox_1, revert_tcolorbox_2,
2575 revert_tcolorbox_3, revert_tcolorbox_4, revert_tcolorbox_5,
2576 revert_tcolorbox_6, revert_tcolorbox_7, revert_tcolorbox_8]],
2577 [496, [revert_external_bbox]],
2578 [495, []], # nothing to do since the noUnzip parameter was optional
2579 [494, [revert_subref]],
2580 [493, [revert_jss]],
2581 [492, [revert_mathmulticol]],
2582 [491, [revert_colorbox]],
2583 [490, [revert_textcolor]],
2584 [489, [revert_origin]],
2585 [488, [revert_BoxFeatures]],
2586 [487, [revert_newgloss, revert_glossgroup]],
2587 [486, [revert_forest]],
2588 [485, [revert_ex_itemargs]],
2589 [484, [revert_sigplan_doi]],
2590 [483, [revert_georgian]],
2591 [482, [revert_specialchar]],
2592 [481, [revert_phrases]],
2593 [480, [revert_dashes]],
2594 [479, [revert_question_env]],
2595 [478, [revert_beamer_lemma]],
2596 [477, [revert_xarrow]],
2597 [476, [revert_swissgerman]],
2598 [475, [revert_smash]],
2599 [474, [revert_separator]]
2603 if __name__ == "__main__":