1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # -*- coding: utf-8 -*-
4 # Copyright (C) 2011 The LyX team
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 """ Convert files to the file format generated by LyX 2.1"""
26 # Uncomment only what you need to import, please.
28 from parser_tools import count_pars_in_inset, del_token, find_token, find_token_exact, \
29 find_token_backwards, find_end_of, find_end_of_inset, find_end_of_layout, \
30 find_end_of_sequence, find_re, get_option_value, get_containing_layout, \
31 get_containing_inset, get_value, get_quoted_value, set_option_value
33 #from parser_tools import find_token, find_end_of, find_tokens, \
34 #find_end_of_inset, find_end_of_layout, \
35 #is_in_inset, del_token, check_token
37 from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, get_ert
39 #from lyx2lyx_tools import insert_to_preamble, \
40 # lyx2latex, latex_length, revert_flex_inset, \
41 # revert_font_attrs, hex2ratio, str2bool
43 ####################################################################
44 # Private helper functions
46 #def remove_option(lines, m, option):
47 #''' removes option from line m. returns whether we did anything '''
48 #l = lines[m].find(option)
51 #val = lines[m][l:].split('"')[1]
52 #lines[m] = lines[m][:l - 1] + lines[m][l+len(option + '="' + val + '"'):]
56 def revert_Argument_to_TeX_brace(document, line, endline, n, nmax, environment, opt):
58 Reverts an InsetArgument to TeX-code
60 revert_Argument_to_TeX_brace(document, LineOfBegin, LineOfEnd, StartArgument, EndArgument, isEnvironment, isOpt)
61 LineOfBegin is the line of the \\begin_layout or \\begin_inset statement
62 LineOfEnd is the line of the \end_layout or \end_inset statement, if "0" is given, the end of the file is used instead
63 StartArgument is the number of the first argument that needs to be converted
64 EndArgument is the number of the last argument that needs to be converted or the last defined one
65 isEnvironment must be true, if the layout is for a LaTeX environment
66 isOpt must be true, if the argument is an optional one
70 while lineArg != -1 and n < nmax + 1:
71 lineArg = find_token(document.body, "\\begin_inset Argument " + str(n), line)
72 if lineArg > endline and endline != 0:
75 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
76 # we have to assure that no other inset is in the Argument
77 beginInset = find_token(document.body, "\\begin_inset", beginPlain)
78 endInset = find_token(document.body, "\\end_inset", beginPlain)
81 while beginInset < endInset and beginInset != -1:
82 beginInset = find_token(document.body, "\\begin_inset", k)
83 endInset = find_token(document.body, "\\end_inset", l)
86 if environment == False:
88 document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}{")
89 del(document.body[lineArg : beginPlain + 1])
92 document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("]")
93 document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("[")
96 document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}")
97 document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("{")
103 def convert_TeX_brace_to_Argument(document, line, n, nmax, inset, environment, opt):
105 Converts TeX code for mandatory arguments to an InsetArgument
106 The conversion of TeX code for optional arguments must be done with another routine
107 !!! Be careful if the braces are different in your case as expected here:
108 - "}{" separates mandatory arguments of commands
109 - "}" + "{" separates mandatory arguments of commands
110 - "}" + " " + "{" separates mandatory arguments of commands
111 - { and } surround a mandatory argument of an environment
113 convert_TeX_brace_to_Argument(document, LineOfBeginLayout/Inset, StartArgument, EndArgument, isInset, isEnvironment, isOpt)
114 LineOfBeginLayout/Inset is the line of the \\begin_layout or \\begin_inset statement
115 StartArgument is the number of the first ERT that needs to be converted
116 EndArgument is the number of the last ERT that needs to be converted
117 isInset must be true, if braces inside an InsetLayout needs to be converted
118 isEnvironment must be true, if the layout is for a LaTeX environment
119 isOpt must be true, if the argument is an optional one
121 Todo: this routine can currently handle only one mandatory argument of environments
124 end_layout = find_end_of_layout(document.body, line)
129 lineERT = find_token(document.body, "\\begin_inset ERT", lineERT, end_layout)
132 if environment == False:
133 end_ERT = find_end_of_inset(document.body, lineERT)
135 document.warning("Can't find end of ERT!!")
137 # Note that this only checks for ][ or }{ at the beginning of a line
139 bracePair = find_token(document.body, "][", lineERT, end_ERT)
141 bracePair = find_token(document.body, "}{", lineERT, end_ERT)
143 end = find_token(document.body, "\\end_inset", bracePair)
144 document.body[lineERT : end_ERT + 1] = ["\\end_layout", "", "\\end_inset"]
146 # in the case that n > 1 we have optional arguments before
147 # therefore detect them if any
149 # first check if there is an argument
150 lineArg = find_token(document.body, "\\begin_inset Argument", line)
151 if lineArg < lineERT and lineArg != -1:
152 # we have an argument, so now search backwards for its end
153 # we must now assure that we don't find other insets like e.g. a newline
154 endInsetArg = lineERT
155 endLayoutArg = endInsetArg
156 while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
157 endInsetArg = endInsetArg - 1
158 endLayoutArg = endInsetArg
159 endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
160 endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
161 line = endInsetArg + 1
163 document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
165 document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
167 document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
172 # no brace pair found
173 # now check the case that we have "}" + "{" in two ERTs
175 endBrace = find_token(document.body, "]", lineERT, end_layout)
177 endBrace = find_token(document.body, "}", lineERT, end_layout)
178 if endBrace == lineERT + 5:
180 beginBrace = find_token(document.body, "[", endBrace, end_layout)
182 beginBrace = find_token(document.body, "{", endBrace, end_layout)
183 # assure that the ERTs are consecutive (11 or 12 depending if there is a space between the ERTs or not)
184 if beginBrance != -1 and (beginBrace == endBrace + 11 or beginBrace == endBrace + 12):
185 end = find_token(document.body, "\\end_inset", beginBrace)
186 document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"]
188 # in the case that n > 1 we have optional arguments before
189 # therefore detect them if any
191 # first check if there is an argument
192 lineArg = find_token(document.body, "\\begin_inset Argument", line)
193 if lineArg < lineERT and lineArg != -1:
194 # we have an argument, so now search backwards for its end
195 # we must now assure that we don't find other insets like e.g. a newline
196 endInsetArg = lineERT
197 endLayoutArg = endInsetArg
198 while endInsetArg != endLayoutArg + 2 and endInsetArg != -1:
199 endInsetArg = endInsetArg - 1
200 endLayoutArg = endInsetArg
201 endInsetArg = find_token_backwards(document.body, "\\end_inset", endInsetArg)
202 endLayoutArg = find_token_backwards(document.body, "\\end_layout", endLayoutArg)
203 line = endInsetArg + 1
205 document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
207 document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
209 document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
212 # set the line where the next argument will be inserted
213 if beginBrace == endBrace + 11:
221 if environment == True:
222 # FIXME This version of the routine does not check for and pass over
223 # arguments before n. So it attempts to process the argument in the
224 # document, no matter what has been specified.
226 # The other branch does do that, but probably that code would be better
227 # in a single location: Skip all those arguments, then process the ones
229 end_ERT = find_end_of_inset(document.body, lineERT)
230 document.warning(str(end_ERT))
232 document.warning("Can't find end of ERT!!")
234 # Note that this only checks for [ or { at the beginning of a line
236 opening = find_token(document.body, "[", lineERT, end_ERT)
238 opening = find_token(document.body, "{", lineERT, end_ERT)
240 lineERT2 = find_token(document.body, "\\begin_inset ERT", end_ERT, end_layout)
242 # argument in a single ERT
243 # strip off the opening bracket
244 document.body[opening] = document.body[opening][1:]
245 ertcontlastline = end_ERT - 3
246 if (opt and document.body[ertcontlastline].endswith("]")) or document.body[ertcontlastline].endswith("}"):
247 # strip off the closing bracket
248 document.body[ertcontlastline] = document.body[ertcontlastline][:-1]
249 end2 = find_token(document.body, "\\end_inset", ertcontlastline)
250 document.body[lineERT : lineERT + 1] = ["\\begin_inset Argument " + str(n)]
252 end_ERT2 = find_end_of_inset(document.body, lineERT2)
254 document.warning("Can't find end of second ERT!!")
257 closing = find_token(document.body, "]", lineERT2, end_ERT2)
259 closing = find_token(document.body, "}", lineERT2, end_ERT2)
260 if closing != -1: # assure that the "}" is in this ERT
261 end2 = find_token(document.body, "\\end_inset", closing)
262 document.body[lineERT2 : end2 + 1] = ["\\end_layout", "", "\\end_inset"]
263 document.body[lineERT : end_ERT + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
266 document.warning("Unable to process argument!")
270 ###############################################################################
272 ### Conversion and reversion routines
274 ###############################################################################
276 def revert_visible_space(document):
277 "Revert InsetSpace visible into its ERT counterpart"
280 i = find_token(document.body, "\\begin_inset space \\textvisiblespace{}", i)
283 end = find_end_of_inset(document.body, i)
284 subst = put_cmd_in_ert("\\textvisiblespace{}")
285 document.body[i:end + 1] = subst
288 undertilde_commands = ["utilde"]
289 def convert_undertilde(document):
290 " Load undertilde automatically "
291 i = find_token(document.header, "\\use_mathdots" , 0)
293 i = find_token(document.header, "\\use_mhchem" , 0)
295 i = find_token(document.header, "\\use_esint" , 0)
297 document.warning("Malformed LyX document: Can't find \\use_mathdots.")
299 j = find_token(document.preamble, "\\usepackage{undertilde}", 0)
301 # package was loaded in the preamble, convert this to header setting for round trip
302 document.header.insert(i + 1, "\\use_undertilde 2") # on
303 del document.preamble[j]
307 j = find_token(document.body, '\\begin_inset Formula', j)
310 k = find_end_of_inset(document.body, j)
312 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(j))
315 code = "\n".join(document.body[j:k])
316 for c in undertilde_commands:
317 if code.find("\\%s" % c) != -1:
318 # at least one of the commands was found - need to switch package off
319 document.header.insert(i + 1, "\\use_undertilde 0") # off
322 # no command was found - set to auto (bug 9069)
323 document.header.insert(i + 1, "\\use_undertilde 1") # auto
327 def revert_undertilde(document):
328 " Load undertilde if used in the document "
329 regexp = re.compile(r'(\\use_undertilde)')
330 i = find_re(document.header, regexp, 0)
331 value = "1" # default is auto
333 value = get_value(document.header, "\\use_undertilde" , i).split()[0]
334 del document.header[i]
335 if value == "2": # on
336 add_to_preamble(document, ["\\usepackage{undertilde}"])
337 elif value == "1": # auto
340 i = find_token(document.body, '\\begin_inset Formula', i)
343 j = find_end_of_inset(document.body, i)
345 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
348 code = "\n".join(document.body[i:j])
349 for c in undertilde_commands:
350 if code.find("\\%s" % c) != -1:
351 add_to_preamble(document, ["\\usepackage{undertilde}"])
356 def revert_negative_space(document):
357 "Revert InsetSpace negmedspace and negthickspace into its TeX-code counterpart"
362 i = find_token(document.body, "\\begin_inset space \\negmedspace{}", i)
364 j = find_token(document.body, "\\begin_inset space \\negthickspace{}", j)
366 # load amsmath in the preamble if not already loaded if we are at the end of checking
368 i = find_token(document.header, "\\use_amsmath 2", 0)
370 add_to_preamble(document, ["\\@ifundefined{negthickspace}{\\usepackage{amsmath}}"])
374 end = find_end_of_inset(document.body, i)
375 subst = put_cmd_in_ert("\\negmedspace{}")
376 document.body[i:end + 1] = subst
377 j = find_token(document.body, "\\begin_inset space \\negthickspace{}", j)
380 end = find_end_of_inset(document.body, j)
381 subst = put_cmd_in_ert("\\negthickspace{}")
382 document.body[j:end + 1] = subst
386 def revert_math_spaces(document):
387 "Revert formulas with protected custom space and protected hfills to TeX-code"
390 i = find_token(document.body, "\\begin_inset Formula", i)
393 j = document.body[i].find("\\hspace*")
395 end = find_end_of_inset(document.body, i)
396 subst = put_cmd_in_ert(document.body[i][21:])
397 document.body[i:end + 1] = subst
401 def convert_japanese_encodings(document):
402 " Rename the japanese encodings to names understood by platex "
404 "EUC-JP-pLaTeX": "euc",
406 "SJIS-pLaTeX": "sjis"
408 i = find_token(document.header, "\\inputencoding" , 0)
411 val = get_value(document.header, "\\inputencoding", i)
412 if val in list(jap_enc_dict.keys()):
413 document.header[i] = "\\inputencoding %s" % jap_enc_dict[val]
416 def revert_japanese_encodings(document):
417 " Revert the japanese encodings name changes "
419 "euc": "EUC-JP-pLaTeX",
421 "sjis": "SJIS-pLaTeX"
423 i = find_token(document.header, "\\inputencoding" , 0)
426 val = get_value(document.header, "\\inputencoding", i)
427 if val in list(jap_enc_dict.keys()):
428 document.header[i] = "\\inputencoding %s" % jap_enc_dict[val]
431 def convert_justification(document):
432 " Add the \\justification buffer param"
433 i = find_token(document.header, "\\suppress_date" , 0)
435 i = find_token(document.header, "\\paperorientation" , 0)
437 i = find_token(document.header, "\\use_indices" , 0)
439 i = find_token(document.header, "\\use_bibtopic" , 0)
441 document.warning("Malformed LyX document: Missing \\suppress_date.")
443 document.header.insert(i + 1, "\\justification true")
446 def revert_justification(document):
447 " Revert the \\justification buffer param"
448 if not del_token(document.header, '\\justification', 0):
449 document.warning("Malformed LyX document: Missing \\justification.")
452 def revert_australian(document):
453 "Set English language variants Australian and Newzealand to English"
455 if document.language == "australian" or document.language == "newzealand":
456 document.language = "english"
457 i = find_token(document.header, "\\language", 0)
459 document.header[i] = "\\language english"
462 j = find_token(document.body, "\\lang australian", j)
464 j = find_token(document.body, "\\lang newzealand", 0)
468 document.body[j] = document.body[j].replace("\\lang newzealand", "\\lang english")
470 document.body[j] = document.body[j].replace("\\lang australian", "\\lang english")
474 def convert_biblio_style(document):
475 "Add a sensible default for \\biblio_style based on the citation engine."
476 i = find_token(document.header, "\\cite_engine", 0)
478 engine = get_value(document.header, "\\cite_engine", i).split("_")[0]
479 style = {"basic": "plain", "natbib": "plainnat", "jurabib": "jurabib"}
480 document.header.insert(i + 1, "\\biblio_style " + style[engine])
483 def revert_biblio_style(document):
484 "BibTeX insets with default option use the style defined by \\biblio_style."
485 i = find_token(document.header, "\\biblio_style" , 0)
487 document.warning("No \\biblio_style line. Nothing to do.")
490 default_style = get_value(document.header, "\\biblio_style", i)
491 del document.header[i]
493 # We are looking for bibtex insets having the default option
496 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
499 j = find_end_of_inset(document.body, i)
501 document.warning("Malformed LyX document: Can't find end of bibtex inset at line " + str(i))
504 k = find_token(document.body, "options", i, j)
506 options = get_quoted_value(document.body, "options", k)
507 if "default" in options.split(","):
508 document.body[k] = 'options "%s"' \
509 % options.replace("default", default_style)
513 def handle_longtable_captions(document, forward):
516 begin_table = find_token(document.body, '<lyxtabular version=', begin_table)
517 if begin_table == -1:
519 end_table = find_end_of(document.body, begin_table, '<lyxtabular', '</lyxtabular>')
521 document.warning("Malformed LyX document: Could not find end of table.")
524 fline = find_token(document.body, "<features", begin_table, end_table)
526 document.warning("Can't find features for inset at line " + str(begin_table))
529 p = document.body[fline].find("islongtable")
534 numrows = get_option_value(document.body[begin_table], "rows")
536 numrows = int(numrows)
538 document.warning(document.body[begin_table])
539 document.warning("Unable to determine rows!")
540 begin_table = end_table
542 begin_row = begin_table
543 for row in range(numrows):
544 begin_row = find_token(document.body, '<row', begin_row, end_table)
546 document.warning("Can't find row " + str(row + 1))
548 end_row = find_end_of(document.body, begin_row, '<row', '</row>')
550 document.warning("Can't find end of row " + str(row + 1))
553 if (get_option_value(document.body[begin_row], 'caption') == 'true' and
554 get_option_value(document.body[begin_row], 'endfirsthead') != 'true' and
555 get_option_value(document.body[begin_row], 'endhead') != 'true' and
556 get_option_value(document.body[begin_row], 'endfoot') != 'true' and
557 get_option_value(document.body[begin_row], 'endlastfoot') != 'true'):
558 document.body[begin_row] = set_option_value(document.body[begin_row], 'caption', 'true", endfirsthead="true')
559 elif get_option_value(document.body[begin_row], 'caption') == 'true':
560 if get_option_value(document.body[begin_row], 'endfirsthead') == 'true':
561 document.body[begin_row] = set_option_value(document.body[begin_row], 'endfirsthead', 'false')
562 if get_option_value(document.body[begin_row], 'endhead') == 'true':
563 document.body[begin_row] = set_option_value(document.body[begin_row], 'endhead', 'false')
564 if get_option_value(document.body[begin_row], 'endfoot') == 'true':
565 document.body[begin_row] = set_option_value(document.body[begin_row], 'endfoot', 'false')
566 if get_option_value(document.body[begin_row], 'endlastfoot') == 'true':
567 document.body[begin_row] = set_option_value(document.body[begin_row], 'endlastfoot', 'false')
569 # since there could be a tabular inside this one, we
570 # cannot jump to end.
574 def convert_longtable_captions(document):
575 "Add a firsthead flag to caption rows"
576 handle_longtable_captions(document, True)
579 def revert_longtable_captions(document):
580 "remove head/foot flag from caption rows"
581 handle_longtable_captions(document, False)
584 def convert_use_packages(document):
585 "use_xxx yyy => use_package xxx yyy"
586 packages = ["amsmath", "esint", "mathdots", "mhchem", "undertilde"]
588 i = find_token(document.header, "\\use_%s" % p, 0)
590 value = get_value(document.header, "\\use_%s" % p, i)
591 document.header[i] = "\\use_package %s %s" % (p, value)
594 def revert_use_packages(document):
595 "use_package xxx yyy => use_xxx yyy"
596 packages = ["amsmath", "esint", "mhchem", "mathdots", "undertilde"]
597 # the order is arbitrary for the use_package version, and not all packages need to be given.
598 # Ensure a complete list and correct order (important for older LyX versions and especially lyx2lyx)
599 # first loop: find line with first package
602 regexp = re.compile(r'(\\use_package\s+%s)' % p)
603 i = find_re(document.header, regexp, 0)
604 if i != -1 and (j < 0 or i < j):
606 # second loop: replace or insert packages in front of all existing ones
608 regexp = re.compile(r'(\\use_package\s+%s)' % p)
609 i = find_re(document.header, regexp, 0)
611 value = get_value(document.header, "\\use_package %s" % p, i).split()[1]
612 del document.header[i]
613 document.header.insert(j, "\\use_%s %s" % (p, value))
615 document.header.insert(j, "\\use_%s 1" % p)
619 def convert_use_package(document, pkg, commands, oldauto):
620 # oldauto defines how the version we are converting from behaves:
621 # if it is true, the old version uses the package automatically.
622 # if it is false, the old version never uses the package.
623 i = find_token(document.header, "\\use_package", 0)
625 document.warning("Malformed LyX document: Can't find \\use_package.")
627 j = find_token(document.preamble, "\\usepackage{" + pkg + "}", 0)
629 # package was loaded in the preamble, convert this to header setting for round trip
630 document.header.insert(i + 1, "\\use_package " + pkg + " 2") # on
631 del document.preamble[j]
632 # If oldauto is true we have two options:
633 # We can either set the package to auto - this is correct for files in
634 # format 425 to 463, and may create a conflict for older files which use
635 # any command in commands with a different definition.
636 # Or we can look whether any command in commands is used, and set it to
637 # auto if not and to off if yes. This will not create a conflict, but will
638 # create uncompilable documents for files in format 425 to 463, which use
639 # any command in commands.
640 # We choose the first option since its error is less likely.
642 document.header.insert(i + 1, "\\use_package " + pkg + " 1") # auto
646 j = find_token(document.body, '\\begin_inset Formula', j)
649 k = find_end_of_inset(document.body, j)
651 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(j))
654 code = "\n".join(document.body[j:k])
656 if code.find("\\%s" % c) != -1:
657 # at least one of the commands was found - need to switch package off
658 document.header.insert(i + 1, "\\use_package " + pkg + " 0") # off
661 # no command was found - set to auto (bug 9069)
662 document.header.insert(i + 1, "\\use_package " + pkg + " 1") # auto
665 def revert_use_package(document, pkg, commands, oldauto):
666 # oldauto defines how the version we are reverting to behaves:
667 # if it is true, the old version uses the package automatically.
668 # if it is false, the old version never uses the package.
669 regexp = re.compile(r'(\\use_package\s+%s)' % pkg)
670 i = find_re(document.header, regexp, 0)
671 value = "1" # default is auto
673 value = get_value(document.header, "\\use_package" , i).split()[1]
674 del document.header[i]
675 if value == "2": # on
676 add_to_preamble(document, ["\\usepackage{" + pkg + "}"])
677 elif value == "1" and not oldauto: # auto
680 i = find_token(document.body, '\\begin_inset Formula', i)
683 j = find_end_of_inset(document.body, i)
685 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
688 code = "\n".join(document.body[i:j])
690 if code.find("\\%s" % c) != -1:
691 add_to_preamble(document, ["\\usepackage{" + pkg + "}"])
696 mathtools_commands = ["mathclap", "mathllap", "mathrlap", \
697 "lgathered", "rgathered", "vcentcolon", "dblcolon", \
698 "coloneqq", "Coloneqq", "coloneq", "Coloneq", "eqqcolon", \
699 "Eqqcolon", "eqcolon", "Eqcolon", "colonapprox", \
700 "Colonapprox", "colonsim", "Colonsim"]
701 def convert_use_mathtools(document):
702 "insert use_package mathtools"
703 convert_use_package(document, "mathtools", mathtools_commands, False)
706 def revert_use_mathtools(document):
707 "remove use_package mathtools"
708 revert_use_package(document, "mathtools", mathtools_commands, False)
711 # commands provided by stmaryrd.sty but LyX uses other packages:
712 # boxdot lightning, bigtriangledown, bigtriangleup
713 stmaryrd_commands = ["shortleftarrow", "shortrightarrow", "shortuparrow", \
714 "shortdownarrow", "Yup", "Ydown", "Yleft", "Yright", \
715 "varcurlyvee", "varcurlywedge", "minuso", "baro", \
716 "sslash", "bbslash", "moo", "varotimes", "varoast", \
717 "varobar", "varodot", "varoslash", "varobslash", \
718 "varocircle", "varoplus", "varominus", "boxast", \
719 "boxbar", "boxslash", "boxbslash", "boxcircle", \
720 "boxbox", "boxempty", "merge", "vartimes", \
721 "fatsemi", "sswarrow", "ssearrow", "curlywedgeuparrow", \
722 "curlywedgedownarrow", "fatslash", "fatbslash", "lbag", \
723 "rbag", "varbigcirc", "leftrightarroweq", \
724 "curlyveedownarrow", "curlyveeuparrow", "nnwarrow", \
725 "nnearrow", "leftslice", "rightslice", "varolessthan", \
726 "varogreaterthan", "varovee", "varowedge", "talloblong", \
727 "interleave", "obar", "obslash", "olessthan", \
728 "ogreaterthan", "ovee", "owedge", "oblong", "inplus", \
729 "niplus", "nplus", "subsetplus", "supsetplus", \
730 "subsetpluseq", "supsetpluseq", "Lbag", "Rbag", \
731 "llbracket", "rrbracket", "llparenthesis", \
732 "rrparenthesis", "binampersand", "bindnasrepma", \
733 "trianglelefteqslant", "trianglerighteqslant", \
734 "ntrianglelefteqslant", "ntrianglerighteqslant", \
735 "llfloor", "rrfloor", "llceil", "rrceil", "arrownot", \
736 "Arrownot", "Mapstochar", "mapsfromchar", "Mapsfromchar", \
737 "leftrightarrowtriangle", "leftarrowtriangle", \
738 "rightarrowtriangle", \
739 "bigcurlyvee", "bigcurlywedge", "bigsqcap", "bigbox", \
740 "bigparallel", "biginterleave", "bignplus", \
741 "varcopyright", "longarrownot", "Longarrownot", \
742 "Mapsto", "mapsfrom", "Mapsfrom" "Longmapsto", \
743 "longmapsfrom", "Longmapsfrom"]
744 def convert_use_stmaryrd(document):
745 "insert use_package stmaryrd"
746 convert_use_package(document, "stmaryrd", stmaryrd_commands, False)
749 def revert_use_stmaryrd(document):
750 "remove use_package stmaryrd"
751 revert_use_package(document, "stmaryrd", stmaryrd_commands, False)
754 stackrel_commands = ["stackrel"]
755 def convert_use_stackrel(document):
756 "insert use_package stackrel"
757 convert_use_package(document, "stackrel", stackrel_commands, False)
760 def revert_use_stackrel(document):
761 "remove use_package stackrel"
762 revert_use_package(document, "stackrel", stackrel_commands, False)
765 def convert_cite_engine_type(document):
766 "Determine the \\cite_engine_type from the citation engine."
767 i = find_token(document.header, "\\cite_engine", 0)
770 engine = get_value(document.header, "\\cite_engine", i)
772 engine, type = engine.split("_")
774 type = {"basic": "numerical", "jurabib": "authoryear"}[engine]
775 document.header[i] = "\\cite_engine " + engine
776 document.header.insert(i + 1, "\\cite_engine_type " + type)
779 def revert_cite_engine_type(document):
780 "Natbib had the type appended with an underscore."
781 engine_type = "numerical"
782 i = find_token(document.header, "\\cite_engine_type" , 0)
784 document.warning("No \\cite_engine_type line. Assuming numerical.")
786 engine_type = get_value(document.header, "\\cite_engine_type", i)
787 del document.header[i]
789 # We are looking for the natbib citation engine
790 i = find_token(document.header, "\\cite_engine natbib", 0)
793 document.header[i] = "\\cite_engine natbib_" + engine_type
796 def convert_cite_engine_type_default(document):
797 "Convert \\cite_engine_type to default for the basic citation engine."
798 i = find_token(document.header, "\\cite_engine basic", 0)
801 i = find_token(document.header, "\\cite_engine_type" , 0)
804 document.header[i] = "\\cite_engine_type default"
807 def revert_cite_engine_type_default(document):
808 """Revert \\cite_engine_type default.
810 Revert to numerical for the basic cite engine, otherwise to authoryear."""
811 engine_type = "authoryear"
812 i = find_token(document.header, "\\cite_engine_type default" , 0)
815 j = find_token(document.header, "\\cite_engine basic", 0)
817 engine_type = "numerical"
818 document.header[i] = "\\cite_engine_type " + engine_type
821 cancel_commands = ["cancel", "bcancel", "xcancel", "cancelto"]
822 # this is the same, as revert_use_cancel() except for the default
823 def revert_cancel(document):
824 "add cancel to the preamble if necessary"
825 revert_use_package(document, "cancel", cancel_commands, False)
828 def revert_verbatim(document, starred = False):
829 " Revert verbatim environments completely to TeX-code. "
833 layout_name = "Verbatim"
834 latex_name = "verbatim"
836 layout_name = "Verbatim*"
837 latex_name = "verbatim*"
839 subst_end = ['\\end_layout', '', '\\begin_layout Plain Layout',
841 '\\begin_layout Plain Layout', '', '',
843 'end{%s}' % (latex_name),
844 '\\end_layout', '', '\\end_inset',
845 '', '', '\\end_layout']
846 subst_begin = ['\\begin_layout Standard', '\\noindent',
847 '\\begin_inset ERT', 'status open', '',
848 '\\begin_layout Plain Layout', '', '', '\\backslash',
849 'begin{%s}' % (latex_name),
850 '\\end_layout', '', '\\begin_layout Plain Layout', '']
853 i = find_token(document.body, "\\begin_layout %s" % (layout_name), i)
856 j = find_end_of_layout(document.body, i)
858 document.warning("Malformed LyX document: Can't find end of %s layout" \
862 # delete all line breaks insets (there are no other insets)
865 n = find_token(document.body, "\\begin_inset Newline newline", l, j)
867 n = find_token(document.body, "\\begin_inset Newline linebreak", l, j)
870 m = find_end_of_inset(document.body, n)
871 del(document.body[m:m+1])
872 document.body[n:n+1] = ['\\end_layout', '', '\\begin_layout Plain Layout']
874 # we deleted a line, so the end of the inset moved forward.
875 # FIXME But we also added some lines, didn't we? I think this
878 # consecutive verbatim environments need to be connected
879 k = find_token(document.body, "\\begin_layout %s" % (layout_name), j)
880 if k == j + 2 and consecutive == False:
882 document.body[j:j+1] = ['\\end_layout', '', '\\begin_layout Plain Layout']
883 document.body[i:i+1] = subst_begin
885 if k == j + 2 and consecutive == True:
886 document.body[j:j+1] = ['\\end_layout', '', '\\begin_layout Plain Layout']
887 del(document.body[i:i+1])
889 if k != j + 2 and consecutive == True:
890 document.body[j:j+1] = subst_end
891 # the next paragraph must not be indented
892 # FIXME This seems to be causing problems, because of the
893 # hardcoded use of 19. We should figure out exactly where
894 # this needs to go by searching for the right tag.
895 document.body[j+19:j+19] = ['\\noindent']
896 del(document.body[i:i+1])
900 document.body[j:j+1] = subst_end
901 # the next paragraph must not be indented
902 # FIXME This seems to be causing problems, because of the
903 # hardcoded use of 19. We should figure out exactly where
904 # this needs to go by searching for the right tag.
905 document.body[j+19:j+19] = ['\\noindent']
906 document.body[i:i+1] = subst_begin
909 def revert_tipa(document):
910 " Revert native TIPA insets to mathed or ERT. "
913 i = find_token(document.body, "\\begin_inset IPA", i)
916 j = find_end_of_inset(document.body, i)
918 document.warning("Malformed LyX document: Can't find end of IPA inset")
922 n = find_token(document.body, "\\begin_layout", i, j)
924 document.warning("Malformed LyX document: IPA inset has no embedded layout")
927 m = find_end_of_layout(document.body, n)
929 document.warning("Malformed LyX document: Can't find end of embedded layout")
932 content = document.body[n+1:m]
933 p = find_token(document.body, "\\begin_layout", m, j)
934 if p != -1 or len(content) > 1:
936 content = document.body[i+1:j]
938 # IPA insets with multiple pars need to be wrapped by \begin{IPA}...\end{IPA}
939 document.body[i:j+1] = ['\\end_layout', '', '\\begin_layout Standard'] + put_cmd_in_ert("\\begin{IPA}") + ['\\end_layout'] + content + ['\\begin_layout Standard'] + put_cmd_in_ert("\\end{IPA}")
940 add_to_preamble(document, ["\\usepackage{tipa,tipx}"])
942 # single-par IPA insets can be reverted to mathed
943 document.body[i:j+1] = ["\\begin_inset Formula $\\text{\\textipa{" + content[0] + "}}$", "\\end_inset"]
947 def revert_cell_rotation(document):
948 "Revert cell rotations to TeX-code"
950 load_rotating = False
954 # first, let's find out if we need to do anything
955 i = find_token(document.body, '<cell ', i)
958 j = document.body[i].find('rotate="')
960 k = document.body[i].find('"', j + 8)
961 value = document.body[i][j + 8 : k]
963 rgx = re.compile(r' rotate="[^"]+?"')
964 # remove rotate option
965 document.body[i] = rgx.sub('', document.body[i])
967 rgx = re.compile(r' rotate="[^"]+?"')
968 document.body[i] = rgx.sub(' rotate="true"', document.body[i])
970 rgx = re.compile(r' rotate="[^"]+?"')
972 # remove rotate option
973 document.body[i] = rgx.sub('', document.body[i])
975 document.body[i + 5 : i + 5] = \
976 put_cmd_in_ert("\\end{turn}")
977 document.body[i + 4 : i + 4] = \
978 put_cmd_in_ert("\\begin{turn}{" + value + "}")
984 add_to_preamble(document, ["\\@ifundefined{turnbox}{\usepackage{rotating}}{}"])
987 def convert_cell_rotation(document):
988 'Convert cell rotation statements from "true" to "90"'
992 # first, let's find out if we need to do anything
993 i = find_token(document.body, '<cell ', i)
996 j = document.body[i].find('rotate="true"')
998 rgx = re.compile(r'rotate="[^"]+?"')
999 # convert "true" to "90"
1000 document.body[i] = rgx.sub('rotate="90"', document.body[i])
1005 def revert_table_rotation(document):
1006 "Revert table rotations to TeX-code"
1008 load_rotating = False
1012 # first, let's find out if we need to do anything
1013 i = find_token(document.body, '<features ', i)
1016 j = document.body[i].find('rotate="')
1018 end_table = find_token(document.body, '</lyxtabular>', j)
1019 k = document.body[i].find('"', j + 8)
1020 value = document.body[i][j + 8 : k]
1022 rgx = re.compile(r' rotate="[^"]+?"')
1023 # remove rotate option
1024 document.body[i] = rgx.sub('', document.body[i])
1026 rgx = re.compile(r'rotate="[^"]+?"')
1027 document.body[i] = rgx.sub('rotate="true"', document.body[i])
1029 rgx = re.compile(r' rotate="[^"]+?"')
1030 load_rotating = True
1031 # remove rotate option
1032 document.body[i] = rgx.sub('', document.body[i])
1034 document.body[end_table + 3 : end_table + 3] = \
1035 put_cmd_in_ert("\\end{turn}")
1036 document.body[i - 2 : i - 2] = \
1037 put_cmd_in_ert("\\begin{turn}{" + value + "}")
1043 add_to_preamble(document, ["\\@ifundefined{turnbox}{\usepackage{rotating}}{}"])
1046 def convert_table_rotation(document):
1047 'Convert table rotation statements from "true" to "90"'
1051 # first, let's find out if we need to do anything
1052 i = find_token(document.body, '<features ', i)
1055 j = document.body[i].find('rotate="true"')
1057 rgx = re.compile(r'rotate="[^"]+?"')
1058 # convert "true" to "90"
1059 document.body[i] = rgx.sub('rotate="90"', document.body[i])
1064 def convert_listoflistings(document):
1065 'Convert ERT \lstlistoflistings to TOC lstlistoflistings inset'
1066 # We can support roundtrip because the command is so simple
1069 i = find_token(document.body, "\\begin_inset ERT", i)
1072 j = find_end_of_inset(document.body, i)
1074 document.warning("Malformed LyX document: Can't find end of ERT inset")
1077 ert = get_ert(document.body, i)
1078 if ert == "\\lstlistoflistings{}":
1079 document.body[i:j] = ["\\begin_inset CommandInset toc", "LatexCommand lstlistoflistings", ""]
1085 def revert_listoflistings(document):
1086 'Convert TOC lstlistoflistings inset to ERT lstlistoflistings'
1089 i = find_token(document.body, "\\begin_inset CommandInset toc", i)
1092 if document.body[i+1] == "LatexCommand lstlistoflistings":
1093 j = find_end_of_inset(document.body, i)
1095 document.warning("Malformed LyX document: Can't find end of TOC inset")
1098 subst = put_cmd_in_ert("\\lstlistoflistings{}")
1099 document.body[i:j+1] = subst
1100 add_to_preamble(document, ["\\usepackage{listings}"])
1104 def convert_use_amssymb(document):
1105 "insert use_package amssymb"
1106 regexp = re.compile(r'(\\use_package\s+amsmath)')
1107 i = find_re(document.header, regexp, 0)
1109 document.warning("Malformed LyX document: Can't find \\use_package amsmath.")
1111 value = get_value(document.header, "\\use_package" , i).split()[1]
1114 useamsmath = int(value)
1116 document.warning("Invalid \\use_package amsmath: " + value + ". Assuming auto.")
1118 j = find_token(document.preamble, "\\usepackage{amssymb}", 0)
1120 document.header.insert(i + 1, "\\use_package amssymb %d" % useamsmath)
1122 document.header.insert(i + 1, "\\use_package amssymb 2")
1123 del document.preamble[j]
1126 def revert_use_amssymb(document):
1127 "remove use_package amssymb"
1128 regexp1 = re.compile(r'(\\use_package\s+amsmath)')
1129 regexp2 = re.compile(r'(\\use_package\s+amssymb)')
1130 i = find_re(document.header, regexp1, 0)
1131 j = find_re(document.header, regexp2, 0)
1132 value1 = "1" # default is auto
1133 value2 = "1" # default is auto
1135 value1 = get_value(document.header, "\\use_package" , i).split()[1]
1137 value2 = get_value(document.header, "\\use_package" , j).split()[1]
1138 del document.header[j]
1139 if value1 != value2 and value2 == "2": # on
1140 add_to_preamble(document, ["\\usepackage{amssymb}"])
1143 def convert_use_cancel(document):
1144 "insert use_package cancel"
1145 convert_use_package(document, "cancel", cancel_commands, True)
1148 def revert_use_cancel(document):
1149 "remove use_package cancel"
1150 revert_use_package(document, "cancel", cancel_commands, True)
1153 def revert_ancientgreek(document):
1154 "Set the document language for ancientgreek to greek"
1156 if document.language == "ancientgreek":
1157 document.language = "greek"
1158 i = find_token(document.header, "\\language", 0)
1160 document.header[i] = "\\language greek"
1163 j = find_token(document.body, "\\lang ancientgreek", j)
1167 document.body[j] = document.body[j].replace("\\lang ancientgreek", "\\lang greek")
1171 def revert_languages(document):
1172 "Set the document language for new supported languages to English"
1175 "coptic", "divehi", "hindi", "kurmanji", "lao", "marathi", "occitan", "sanskrit",
1176 "syriac", "tamil", "telugu", "urdu"
1178 for n in range(len(languages)):
1179 if document.language == languages[n]:
1180 document.language = "english"
1181 i = find_token(document.header, "\\language", 0)
1183 document.header[i] = "\\language english"
1185 while j < len(document.body):
1186 j = find_token(document.body, "\\lang " + languages[n], j)
1188 document.body[j] = document.body[j].replace("\\lang " + languages[n], "\\lang english")
1191 j = len(document.body)
1194 def convert_armenian(document):
1195 "Use polyglossia and thus non-TeX fonts for Armenian"
1197 if document.language == "armenian":
1198 i = find_token(document.header, "\\use_non_tex_fonts", 0)
1200 document.header[i] = "\\use_non_tex_fonts true"
1203 def revert_armenian(document):
1204 "Use ArmTeX and thus TeX fonts for Armenian"
1206 if document.language == "armenian":
1207 i = find_token(document.header, "\\use_non_tex_fonts", 0)
1209 document.header[i] = "\\use_non_tex_fonts false"
1212 def revert_libertine(document):
1213 " Revert native libertine font definition to LaTeX "
1215 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1216 i = find_token(document.header, "\\font_roman libertine", 0)
1219 j = find_token(document.header, "\\font_osf true", 0)
1222 preamble = "\\usepackage"
1224 document.header[j] = "\\font_osf false"
1227 preamble += "[lining]"
1228 preamble += "{libertine-type1}"
1229 add_to_preamble(document, [preamble])
1230 document.header[i] = "\\font_roman default"
1233 def revert_txtt(document):
1234 " Revert native txtt font definition to LaTeX "
1236 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1237 i = find_token(document.header, "\\font_typewriter txtt", 0)
1239 preamble = "\\renewcommand{\\ttdefault}{txtt}"
1240 add_to_preamble(document, [preamble])
1241 document.header[i] = "\\font_typewriter default"
1244 def revert_mathdesign(document):
1245 " Revert native mathdesign font definition to LaTeX "
1247 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1253 i = find_token(document.header, "\\font_roman", 0)
1256 val = get_value(document.header, "\\font_roman", i)
1257 if val in list(mathdesign_dict.keys()):
1258 preamble = "\\usepackage[%s" % mathdesign_dict[val]
1260 j = find_token(document.header, "\\font_osf true", 0)
1263 document.header[j] = "\\font_osf false"
1264 l = find_token(document.header, "\\font_sc true", 0)
1267 document.header[l] = "\\font_sc false"
1269 preamble += ",expert"
1270 preamble += "]{mathdesign}"
1271 add_to_preamble(document, [preamble])
1272 document.header[i] = "\\font_roman default"
1275 def revert_texgyre(document):
1276 " Revert native TeXGyre font definition to LaTeX "
1278 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1279 texgyre_fonts = ["tgadventor", "tgbonum", "tgchorus", "tgcursor", \
1280 "tgheros", "tgpagella", "tgschola", "tgtermes"]
1281 i = find_token(document.header, "\\font_roman", 0)
1283 val = get_value(document.header, "\\font_roman", i)
1284 if val in texgyre_fonts:
1285 preamble = "\\usepackage{%s}" % val
1286 add_to_preamble(document, [preamble])
1287 document.header[i] = "\\font_roman default"
1288 i = find_token(document.header, "\\font_sans", 0)
1290 val = get_value(document.header, "\\font_sans", i)
1291 if val in texgyre_fonts:
1292 preamble = "\\usepackage{%s}" % val
1293 add_to_preamble(document, [preamble])
1294 document.header[i] = "\\font_sans default"
1295 i = find_token(document.header, "\\font_typewriter", 0)
1297 val = get_value(document.header, "\\font_typewriter", i)
1298 if val in texgyre_fonts:
1299 preamble = "\\usepackage{%s}" % val
1300 add_to_preamble(document, [preamble])
1301 document.header[i] = "\\font_typewriter default"
1304 def revert_ipadeco(document):
1305 " Revert IPA decorations to ERT "
1308 i = find_token(document.body, "\\begin_inset IPADeco", i)
1311 end = find_end_of_inset(document.body, i)
1313 document.warning("Can't find end of inset at line " + str(i))
1316 line = document.body[i]
1317 rx = re.compile(r'\\begin_inset IPADeco (.*)$')
1319 decotype = m.group(1)
1320 if decotype != "toptiebar" and decotype != "bottomtiebar":
1321 document.warning("Invalid IPADeco type: " + decotype)
1324 blay = find_token(document.body, "\\begin_layout Plain Layout", i, end)
1326 document.warning("Can't find layout for inset at line " + str(i))
1329 bend = find_end_of_layout(document.body, blay)
1331 document.warning("Malformed LyX document: Could not find end of IPADeco inset's layout.")
1334 substi = ["\\begin_inset ERT", "status collapsed", "",
1335 "\\begin_layout Plain Layout", "", "", "\\backslash",
1336 decotype + "{", "\\end_layout", "", "\\end_inset"]
1337 substj = ["\\size default", "", "\\begin_inset ERT", "status collapsed", "",
1338 "\\begin_layout Plain Layout", "", "}", "\\end_layout", "", "\\end_inset"]
1339 # do the later one first so as not to mess up the numbering
1340 document.body[bend:end + 1] = substj
1341 document.body[i:blay + 1] = substi
1342 i = end + len(substi) + len(substj) - (end - bend) - (blay - i) - 2
1343 add_to_preamble(document, "\\usepackage{tipa}")
1346 def revert_ipachar(document):
1347 ' Revert \\IPAChar to ERT '
1350 while i < len(document.body):
1351 m = re.match(r'(.*)\\IPAChar \\(\w+\{\w+\})(.*)', document.body[i])
1355 ipachar = m.group(2)
1358 '\\begin_inset ERT',
1359 'status collapsed', '',
1360 '\\begin_layout Standard',
1361 '', '', '\\backslash',
1366 document.body[i: i+1] = subst
1371 add_to_preamble(document, "\\usepackage{tone}")
1374 def revert_minionpro(document):
1375 " Revert native MinionPro font definition to LaTeX "
1377 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1378 i = find_token(document.header, "\\font_roman minionpro", 0)
1381 j = find_token(document.header, "\\font_osf true", 0)
1384 preamble = "\\usepackage"
1386 document.header[j] = "\\font_osf false"
1389 preamble += "{MinionPro}"
1390 add_to_preamble(document, [preamble])
1391 document.header[i] = "\\font_roman default"
1394 def revert_mathfonts(document):
1395 " Revert native math font definitions to LaTeX "
1397 i = find_token(document.header, "\\font_math", 0)
1400 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1401 val = get_value(document.header, "\\font_math", i)
1402 if val == "eulervm":
1403 add_to_preamble(document, "\\usepackage{eulervm}")
1404 elif val == "default":
1406 "lmodern": "\\renewcommand{\\rmdefault}{lmr}",
1407 "minionpro": "\\usepackage[onlytext,lf]{MinionPro}",
1408 "minionpro-osf": "\\usepackage[onlytext]{MinionPro}",
1409 "palatino": "\\renewcommand{\\rmdefault}{ppl}",
1410 "palatino-osf": "\\renewcommand{\\rmdefault}{pplj}",
1411 "times": "\\renewcommand{\\rmdefault}{ptm}",
1412 "utopia": "\\renewcommand{\\rmdefault}{futs}",
1413 "utopia-osf": "\\renewcommand{\\rmdefault}{futj}",
1415 j = find_token(document.header, "\\font_roman", 0)
1417 rm = get_value(document.header, "\\font_roman", j)
1418 k = find_token(document.header, "\\font_osf true", 0)
1421 if rm in list(mathfont_dict.keys()):
1422 add_to_preamble(document, mathfont_dict[rm])
1423 document.header[j] = "\\font_roman default"
1425 document.header[k] = "\\font_osf false"
1426 del document.header[i]
1429 def revert_mdnomath(document):
1430 " Revert mathdesign and fourier without math "
1432 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1434 "md-charter": "mdbch",
1435 "md-utopia": "mdput",
1436 "md-garamond": "mdugm"
1438 i = find_token(document.header, "\\font_roman", 0)
1441 val = get_value(document.header, "\\font_roman", i)
1442 if val in list(mathdesign_dict.keys()):
1443 j = find_token(document.header, "\\font_math", 0)
1445 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1446 mval = get_value(document.header, "\\font_math", j)
1447 if mval == "default":
1448 document.header[i] = "\\font_roman default"
1449 add_to_preamble(document, "\\renewcommand{\\rmdefault}{%s}" % mathdesign_dict[val])
1451 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1454 def convert_mathfonts(document):
1455 document.header.insert(-1, "\\font_math auto")
1458 def convert_mdnomath(document):
1459 " Change mathdesign font name "
1461 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1463 "mdbch": "md-charter",
1464 "mdput": "md-utopia",
1465 "mdugm": "md-garamond"
1467 i = find_token(document.header, "\\font_roman", 0)
1470 val = get_value(document.header, "\\font_roman", i)
1471 if val in list(mathdesign_dict.keys()):
1472 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1475 def revert_newtxmath(document):
1476 " Revert native newtxmath definitions to LaTeX "
1478 i = find_token(document.header, "\\font_math", 0)
1481 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1482 val = get_value(document.header, "\\font_math", i)
1484 "libertine-ntxm": "\\usepackage[libertine]{newtxmath}",
1485 "minion-ntxm": "\\usepackage[minion]{newtxmath}",
1486 "newtxmath": "\\usepackage{newtxmath}",
1488 if val in list(mathfont_dict.keys()):
1489 add_to_preamble(document, mathfont_dict[val])
1490 document.header[i] = "\\font_math auto"
1493 def revert_biolinum(document):
1494 " Revert native biolinum font definition to LaTeX "
1496 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1497 i = find_token(document.header, "\\font_sans biolinum", 0)
1500 j = find_token(document.header, "\\font_osf true", 0)
1503 preamble = "\\usepackage"
1506 preamble += "{biolinum-type1}"
1507 add_to_preamble(document, [preamble])
1508 document.header[i] = "\\font_sans default"
1511 def revert_uop(document):
1512 " Revert native URW Classico (Optima) font definition to LaTeX "
1514 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1515 i = find_token(document.header, "\\font_sans uop", 0)
1517 preamble = "\\renewcommand{\\sfdefault}{uop}"
1518 add_to_preamble(document, [preamble])
1519 document.header[i] = "\\font_sans default"
1522 def convert_latexargs(document):
1523 " Convert InsetArgument to new syntax "
1525 if find_token(document.body, "\\begin_inset Argument", 0) == -1:
1529 # A list of layouts (document classes) with only optional or no arguments.
1530 # These can be safely converted to the new syntax
1531 # (I took the liberty to add some of my personal layouts/modules here; JSP)
1532 safe_layouts = ["aa", "aapaper", "aastex", "achemso", "acmsiggraph", "AEA",
1533 "agu-dtd", "agums", "agutex", "amsart", "amsbook", "apa",
1534 "arab-article", "armenian-article", "article-beamer", "article",
1535 "beamer", "book", "broadway", "chess", "cl2emult", "ctex-article",
1536 "ctex-book", "ctex-report", "dinbrief", "docbook-book", "docbook-chapter",
1537 "docbook", "docbook-section", "doublecol-new", "dtk", "ectaart", "egs",
1538 "elsarticle", "elsart", "entcs", "europecv", "extarticle", "extbook",
1539 "extletter", "extreport", "foils", "frletter", "g-brief2", "g-brief",
1540 "heb-article", "heb-letter", "hollywood", "IEEEtran", "ijmpc", "ijmpd",
1541 "iopart", "isprs", "jarticle", "jasatex", "jbook", "jgrga", "jreport",
1542 "jsarticle", "jsbeamer", "jsbook", "jss", "kluwer", "latex8", "letter", "lettre",
1543 "literate-article", "literate-book", "literate-report", "llncs", "ltugboat",
1544 "memoir", "moderncv", "mwart", "mwbk", "mwrep", "paper", "powerdot",
1545 "recipebook", "report", "revtex4", "revtex", "scrartcl", "scrarticle-beamer",
1546 "scrbook", "scrlettr", "scrlttr2", "scrreprt", "seminar", "siamltex",
1547 "sigplanconf", "simplecv", "singlecol", "singlecol-new", "slides", "spie",
1548 "svglobal3", "svglobal", "svjog", "svmono", "svmult", "svprobth", "tarticle",
1549 "tbook", "treport", "tufte-book", "tufte-handout"]
1550 # A list of "safe" modules, same as above
1551 safe_modules = ["biblatex", "beameraddons", "beamer-resenumerate", "beamersession", "braille",
1552 "customHeadersFooters", "endnotes", "enumitem", "eqs-within-sections", "figs-within-sections",
1553 "fix-cm", "fixltx2e", "foottoend", "hanging", "jscharstyles", "knitr", "lilypond",
1554 "linguistics", "linguisticx", "logicalmkup", "minimalistic", "nomindex", "noweb",
1555 "pdfcomment", "sweave", "tabs-within-sections", "theorems-ams-bytype",
1556 "theorems-ams-extended-bytype", "theorems-ams-extended", "theorems-ams", "theorems-bytype",
1557 "theorems-chap-bytype", "theorems-chap", "theorems-named", "theorems-sec-bytype",
1558 "theorems-sec", "theorems-starred", "theorems-std", "todonotes"]
1559 # Modules we need to take care of
1560 caveat_modules = ["initials"]
1561 # information about the relevant styles in caveat_modules (number of opt and req args)
1562 # use this if we get more caveat_modules. For now, use hard coding (see below).
1563 # initials = [{'Layout' : 'Initial', 'opt' : 1, 'req' : 1}]
1565 # Is this a known safe layout?
1566 safe_layout = document.textclass in safe_layouts
1568 document.warning("Lyx2lyx knows nothing about textclass '%s'. "
1569 "Please check if short title insets have been converted correctly."
1570 % document.textclass)
1571 # Do we use unsafe or unknown modules
1572 mods = document.get_module_list()
1573 unknown_modules = False
1574 used_caveat_modules = list()
1576 if mod in safe_modules:
1578 if mod in caveat_modules:
1579 used_caveat_modules.append(mod)
1581 unknown_modules = True
1582 document.warning("Lyx2lyx knows nothing about module '%s'. "
1583 "Please check if short title insets have been converted correctly."
1588 i = find_token(document.body, "\\begin_inset Argument", i)
1592 if not safe_layout or unknown_modules:
1593 # We cannot do more here since we have no access to this layout.
1594 # InsetArgument itself will do the real work
1595 # (see InsetArgument::updateBuffer())
1596 document.body[i] = "\\begin_inset Argument 999"
1600 # Find containing paragraph layout
1601 parent = get_containing_layout(document.body, i)
1603 document.warning("Malformed LyX document: Can't find parent paragraph layout")
1610 if len(used_caveat_modules) > 0:
1611 # We know for now that this must be the initials module with the Initial layout
1612 # If we get more such modules, we need some automating.
1613 if parent[0] == "Initial":
1614 # Layout has 1 opt and 1 req arg.
1615 # Count the actual arguments
1617 for p in range(parbeg, parend):
1618 if document.body[p] == "\\begin_inset Argument":
1623 # Collect all arguments in this paragraph
1625 for p in range(parbeg, parend):
1626 if document.body[p] == "\\begin_inset Argument":
1628 if allowed_opts != -1:
1629 # We have less arguments than opt + required.
1630 # required must take precedence.
1631 if argnr > allowed_opts and argnr < first_req:
1633 document.body[p] = "\\begin_inset Argument %d" % argnr
1637 def revert_latexargs(document):
1638 " Revert InsetArgument to old syntax "
1641 rx = re.compile(r'^\\begin_inset Argument (\d+)$')
1644 # Search for Argument insets
1645 i = find_token(document.body, "\\begin_inset Argument", i)
1648 m = rx.match(document.body[i])
1650 # No ID: inset already reverted
1653 # Find containing paragraph layout
1654 parent = get_containing_layout(document.body, i)
1656 document.warning("Malformed LyX document: Can't find parent paragraph layout")
1661 # Do not set realparbeg to parent[3], since this does not work if we
1662 # have another inset (e.g. label or index) before the first argument
1663 # inset (this is the case in the user guide of LyX 2.0.8)
1665 # Collect all arguments in this paragraph
1667 for p in range(parbeg, parend):
1668 m = rx.match(document.body[p])
1671 # This is the first argument inset
1673 val = int(m.group(1))
1674 j = find_end_of_inset(document.body, p)
1675 # Revert to old syntax
1676 document.body[p] = "\\begin_inset Argument"
1678 document.warning("Malformed LyX document: Can't find end of Argument inset")
1681 args[val] = document.body[p : j + 1]
1683 realparend = realparend - len(document.body[p : j + 1])
1684 # Remove arg inset at this position
1685 del document.body[p : j + 1]
1689 # No argument inset found
1690 realparbeg = parent[3]
1691 # Now sort the arg insets
1693 for f in sorted(args):
1696 # Insert the sorted arg insets at paragraph begin
1697 document.body[realparbeg : realparbeg] = subst
1699 i = realparbeg + 1 + len(subst)
1702 def revert_IEEEtran(document):
1704 Reverts InsetArgument of
1707 Biography without photo
1710 if document.textclass != "IEEEtran":
1713 layouts = {"Page headings": False,
1714 "Biography without photo": True}
1716 for layout in list(layouts.keys()):
1719 i = find_token(document.body, '\\begin_layout ' + layout, i)
1722 revert_Argument_to_TeX_brace(document, i, 0, 1, 1, layouts[layout], False)
1727 i = find_token(document.body, '\\begin_inset Flex Paragraph Start', i)
1730 revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1735 i = find_token_exact(document.body, "\\begin_layout Biography", i)
1739 if document.body[i] == "\\begin_layout Biography without photo":
1743 # start with the second argument, therefore 2
1744 revert_Argument_to_TeX_brace(document, i, 0, 2, 2, True, False)
1748 def revert_IEEEtran_2(document):
1750 Reverts Flex Paragraph Start to TeX-code
1752 if document.textclass == "IEEEtran":
1755 begin = find_token(document.body, "\\begin_inset Flex Paragraph Start", begin)
1758 end1 = find_end_of_inset(document.body, begin)
1759 document.body[end1 - 2 : end1 + 1] = put_cmd_in_ert("}")
1760 document.body[begin : begin + 4] = put_cmd_in_ert("\\IEEEPARstart{")
1764 def convert_IEEEtran(document):
1769 Biography without photo
1772 if document.textclass != "IEEEtran":
1775 layouts = {"Page headings": False,
1776 "Biography without photo": True}
1778 for layout in list(layouts.keys()):
1781 i = find_token(document.body, '\\begin_layout ' + layout, i)
1784 convert_TeX_brace_to_Argument(document, i, 1, 1, False, layouts[layout], False)
1789 i = find_token_exact(document.body, "\\begin_layout Biography", i)
1793 if document.body[i] == "\\begin_layout Biography without photo":
1797 # the argument we want to convert is the second one
1798 convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, False)
1802 def revert_AASTeX(document):
1803 " Reverts InsetArgument of Altaffilation to TeX-code "
1804 if document.textclass == "aastex":
1807 i = find_token(document.body, "\\begin_layout Altaffilation", i)
1810 revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1814 def convert_AASTeX(document):
1815 " Converts ERT of Altaffilation to InsetArgument "
1816 if document.textclass == "aastex":
1819 i = find_token(document.body, "\\begin_layout Altaffilation", i)
1822 convert_TeX_brace_to_Argument(document, i, 1, 1, False, False, False)
1826 def revert_AGUTeX(document):
1827 " Reverts InsetArgument of Author affiliation to TeX-code "
1828 if document.textclass == "agutex":
1831 i = find_token(document.body, "\\begin_layout Author affiliation", i)
1834 revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1838 def convert_AGUTeX(document):
1839 " Converts ERT of Author affiliation to InsetArgument "
1840 if document.textclass == "agutex":
1843 i = find_token(document.body, "\\begin_layout Author affiliation", i)
1846 convert_TeX_brace_to_Argument(document, i, 1, 1, False, False, False)
1850 def revert_IJMP(document):
1851 " Reverts InsetArgument of MarkBoth to TeX-code "
1852 if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1855 i = find_token(document.body, "\\begin_layout MarkBoth", i)
1858 revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1862 def convert_IJMP(document):
1863 " Converts ERT of MarkBoth to InsetArgument "
1864 if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1867 i = find_token(document.body, "\\begin_layout MarkBoth", i)
1870 convert_TeX_brace_to_Argument(document, i, 1, 1, False, False, False)
1874 def revert_SIGPLAN(document):
1875 " Reverts InsetArguments of SIGPLAN to TeX-code "
1876 if document.textclass == "sigplanconf":
1881 i = find_token(document.body, "\\begin_layout Conference", i)
1883 revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1886 j = find_token(document.body, "\\begin_layout Author", j)
1888 revert_Argument_to_TeX_brace(document, j, 0, 1, 2, False, False)
1890 if i == -1 and j == -1:
1894 def convert_SIGPLAN(document):
1895 " Converts ERT of SIGPLAN to InsetArgument "
1896 if document.textclass == "sigplanconf":
1901 i = find_token(document.body, "\\begin_layout Conference", i)
1903 convert_TeX_brace_to_Argument(document, i, 1, 1, False, False, False)
1906 j = find_token(document.body, "\\begin_layout Author", j)
1908 convert_TeX_brace_to_Argument(document, j, 1, 2, False, False, False)
1910 if i == -1 and j == -1:
1914 def revert_SIGGRAPH(document):
1915 " Reverts InsetArgument of Flex CRcat to TeX-code "
1916 if document.textclass == "acmsiggraph":
1919 i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1922 revert_Argument_to_TeX_brace(document, i, 0, 1, 3, False, False)
1926 def convert_SIGGRAPH(document):
1927 " Converts ERT of Flex CRcat to InsetArgument "
1928 if document.textclass == "acmsiggraph":
1931 i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1934 convert_TeX_brace_to_Argument(document, i, 1, 3, True, False, False)
1938 def revert_EuropeCV(document):
1939 " Reverts InsetArguments of europeCV to TeX-code "
1940 if document.textclass == "europecv":
1947 i = find_token(document.body, "\\begin_layout Item", i)
1949 revert_Argument_to_TeX_brace(document, i, 0, 2, 2, False, False)
1952 j = find_token(document.body, "\\begin_layout BulletedItem", j)
1954 revert_Argument_to_TeX_brace(document, j, 0, 2, 2, False, False)
1957 k = find_token(document.body, "\\begin_layout Language", k)
1959 revert_Argument_to_TeX_brace(document, k, 0, 2, 6, False, False)
1962 m = find_token(document.body, "\\begin_layout LastLanguage", m)
1964 revert_Argument_to_TeX_brace(document, m, 0, 2, 6, False, False)
1966 if i == -1 and j == -1 and k == -1 and m == -1:
1970 def convert_EuropeCV(document):
1971 " Converts ERT of europeCV to InsetArgument "
1972 if document.textclass == "europecv":
1979 i = find_token(document.body, "\\begin_layout Item", i)
1981 convert_TeX_brace_to_Argument(document, i, 2, 2, False, False, False)
1984 j = find_token(document.body, "\\begin_layout BulletedItem", j)
1986 convert_TeX_brace_to_Argument(document, j, 2, 2, False, False, False)
1989 k = find_token(document.body, "\\begin_layout Language", k)
1991 convert_TeX_brace_to_Argument(document, k, 2, 6, False, False, False)
1994 m = find_token(document.body, "\\begin_layout LastLanguage", m)
1996 convert_TeX_brace_to_Argument(document, m, 2, 6, False, False, False)
1998 if i == -1 and j == -1 and k == -1 and m == -1:
2002 def revert_ModernCV(document):
2003 " Reverts InsetArguments of modernCV to TeX-code "
2004 if document.textclass == "moderncv":
2012 j = find_token(document.body, "\\begin_layout Entry", j)
2014 revert_Argument_to_TeX_brace(document, j, 0, 1, 5, False, False)
2017 k = find_token(document.body, "\\begin_layout Item", k)
2019 revert_Argument_to_TeX_brace(document, k, 0, 1, 1, False, False)
2022 m = find_token(document.body, "\\begin_layout ItemWithComment", m)
2024 revert_Argument_to_TeX_brace(document, m, 0, 1, 2, False, False)
2025 document.body[m] = document.body[m].replace("\\begin_layout ItemWithComment", "\\begin_layout Language")
2028 o = find_token(document.body, "\\begin_layout DoubleItem", o)
2030 revert_Argument_to_TeX_brace(document, o, 0, 1, 3, False, False)
2031 document.body[o] = document.body[o].replace("\\begin_layout DoubleItem", "\\begin_layout Computer")
2034 p = find_token(document.body, "\\begin_layout Social", p)
2036 revert_Argument_to_TeX_brace(document, p, 0, 1, 1, False, True)
2038 if j == -1 and k == -1 and m == -1 and o == -1 and p == -1:
2042 def revert_ModernCV_2(document):
2043 " Reverts the Flex:Column inset of modernCV to TeX-code "
2044 if document.textclass == "moderncv":
2048 flex = find_token(document.body, "\\begin_inset Flex Column", flex)
2051 flexEnd = find_end_of_inset(document.body, flex)
2052 wasOpt = revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, False, True)
2053 revert_Argument_to_TeX_brace(document, flex, 0, 2, 2, False, False)
2054 flexEnd = find_end_of_inset(document.body, flex)
2056 document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\cvcolumn")
2058 document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\cvcolumn{")
2059 document.body[flexEnd + 4 : flexEnd + 7] = put_cmd_in_ert("}")
2063 def revert_ModernCV_3(document):
2064 " Reverts the Column style of modernCV to TeX-code "
2065 if document.textclass == "moderncv":
2066 # revert the layouts
2067 revert_ModernCV(document)
2069 # get the position of the end of the last column inset
2070 LastFlexEnd = revert_ModernCV_2(document)
2072 p = find_token(document.body, "\\begin_layout Columns", p)
2075 pEnd = find_end_of_layout(document.body, p)
2076 document.body[p] = document.body[p].replace("\\begin_layout Columns", "\\begin_layout Standard")
2077 if LastFlexEnd != -1:
2078 document.body[p + 1 : p + 1] = put_cmd_in_ert("\\begin{cvcolumns}")
2079 document.body[LastFlexEnd + 24 : LastFlexEnd + 24] = put_cmd_in_ert("\\end{cvcolumns}")
2083 def revert_ModernCV_4(document):
2084 " Reverts the style Social to TeX-code "
2085 if document.textclass == "moderncv":
2086 # revert the layouts
2087 revert_ModernCV(document)
2090 p = find_token(document.body, "\\begin_layout Social", p)
2093 pEnd = find_end_of_layout(document.body, p)
2094 document.body[p] = document.body[p].replace("\\begin_layout Social", "\\begin_layout Standard")
2095 document.body[p + 1 : p + 1] = put_cmd_in_ert("\\social")
2096 hasOpt = find_token(document.body, "[", p + 9)
2098 document.body[p + 30 : p + 30] = put_cmd_in_ert("{")
2099 document.body[p + 41 : p + 41] = put_cmd_in_ert("}")
2101 document.body[p + 11 : p + 11] = put_cmd_in_ert("{")
2102 document.body[p + 21 : p + 21] = put_cmd_in_ert("}")
2106 def convert_ModernCV(document):
2107 " Converts ERT of modernCV to InsetArgument "
2108 if document.textclass == "moderncv":
2116 i = find_token(document.body, "\\begin_layout DoubleItem", i)
2118 convert_TeX_brace_to_Argument(document, i, 1, 1, False, False, False)
2119 document.body[o] = document.body[o].replace("\\begin_layout DoubleItem", "\\begin_layout DoubleListItem")
2122 j = find_token(document.body, "\\begin_layout Entry", j)
2124 convert_TeX_brace_to_Argument(document, j, 1, 5, False, False, False)
2127 k = find_token(document.body, "\\begin_layout Item", k)
2129 convert_TeX_brace_to_Argument(document, k, 1, 1, False, False, False)
2132 m = find_token(document.body, "\\begin_layout Language", m)
2134 convert_TeX_brace_to_Argument(document, m, 1, 2, False, False, False)
2136 if i == -1 and j == -1 and k == -1 and m == -1:
2140 def revert_Initials(document):
2141 " Reverts InsetArgument of Initial to TeX-code "
2144 i = find_token(document.body, "\\begin_layout Initial", i)
2147 # first arg (optional) and second arg (first mandatory) are supported in LyX 2.0.x
2148 revert_Argument_to_TeX_brace(document, i, 0, 3, 3, False, False)
2152 def convert_Initials(document):
2153 " Converts ERT of Initial to InsetArgument "
2156 i = find_token(document.body, "\\begin_layout Initial", i)
2159 convert_TeX_brace_to_Argument(document, i, 3, 3, False, False, False)
2163 def revert_literate(document):
2164 " Revert Literate document to old format "
2165 if del_token(document.header, "noweb", 0):
2166 document.textclass = "literate-" + document.textclass
2169 i = find_token(document.body, "\\begin_layout Chunk", i)
2172 document.body[i] = "\\begin_layout Scrap"
2176 def convert_literate(document):
2177 " Convert Literate document to new format"
2178 i = find_token(document.header, "\\textclass", 0)
2179 if (i != -1) and "literate-" in document.header[i]:
2180 document.textclass = document.header[i].replace("\\textclass literate-", "")
2181 j = find_token(document.header, "\\begin_modules", 0)
2183 document.header.insert(j + 1, "noweb")
2185 document.header.insert(i + 1, "\\end_modules")
2186 document.header.insert(i + 1, "noweb")
2187 document.header.insert(i + 1, "\\begin_modules")
2190 i = find_token(document.body, "\\begin_layout Scrap", i)
2193 document.body[i] = "\\begin_layout Chunk"
2197 def revert_itemargs(document):
2198 " Reverts \\item arguments to TeX-code "
2201 i = find_token(document.body, "\\begin_inset Argument item:", i)
2204 j = find_end_of_inset(document.body, i)
2205 # Find containing paragraph layout
2206 parent = get_containing_layout(document.body, i)
2208 document.warning("Malformed LyX document: Can't find parent paragraph layout")
2212 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2213 endPlain = find_end_of_layout(document.body, beginPlain)
2214 content = document.body[beginPlain + 1 : endPlain]
2215 del document.body[i:j+1]
2216 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2217 document.body[parbeg : parbeg] = subst
2221 def revert_garamondx_newtxmath(document):
2222 " Revert native garamond newtxmath definition to LaTeX "
2224 i = find_token(document.header, "\\font_math", 0)
2227 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
2228 val = get_value(document.header, "\\font_math", i)
2229 if val == "garamondx-ntxm":
2230 add_to_preamble(document, "\\usepackage[garamondx]{newtxmath}")
2231 document.header[i] = "\\font_math auto"
2234 def revert_garamondx(document):
2235 " Revert native garamond font definition to LaTeX "
2237 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
2238 i = find_token(document.header, "\\font_roman garamondx", 0)
2241 j = find_token(document.header, "\\font_osf true", 0)
2244 preamble = "\\usepackage"
2246 preamble += "[osfI]"
2247 preamble += "{garamondx}"
2248 add_to_preamble(document, [preamble])
2249 document.header[i] = "\\font_roman default"
2252 def convert_beamerargs(document):
2253 " Converts beamer arguments to new layout "
2255 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2256 if document.textclass not in beamer_classes:
2259 shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2260 list_layouts = ["Itemize", "Enumerate", "Description"]
2261 rx = re.compile(r'^\\begin_inset Argument (\d+)$')
2265 i = find_token(document.body, "\\begin_inset Argument", i)
2268 # Find containing paragraph layout
2269 parent = get_containing_layout(document.body, i)
2271 document.warning("Malformed LyX document: Can't find parent paragraph layout")
2276 layoutname = parent[0]
2277 for p in range(parbeg, parend):
2278 if layoutname in shifted_layouts:
2279 m = rx.match(document.body[p])
2281 argnr = int(m.group(1))
2283 document.body[p] = "\\begin_inset Argument %d" % argnr
2284 if layoutname == "AgainFrame":
2285 m = rx.match(document.body[p])
2287 document.body[p] = "\\begin_inset Argument 3"
2288 if document.body[p + 4] == "\\begin_inset ERT":
2289 if document.body[p + 9].startswith("<"):
2290 # This is an overlay specification
2292 document.body[p + 9] = document.body[p + 9][1:]
2293 if document.body[p + 9].endswith(">"):
2295 document.body[p + 9] = document.body[p + 9][:-1]
2297 document.body[p] = "\\begin_inset Argument 2"
2298 if layoutname in list_layouts:
2299 m = rx.match(document.body[p])
2301 if m.group(1) == "1":
2302 if document.body[p + 4] == "\\begin_inset ERT":
2303 if document.body[p + 9].startswith("<"):
2304 # This is an overlay specification
2306 document.body[p + 9] = document.body[p + 9][1:]
2307 if document.body[p + 9].endswith(">"):
2309 document.body[p + 9] = document.body[p + 9][:-1]
2310 elif document.body[p + 4].startswith("<"):
2311 # This is an overlay specification (without ERT)
2313 document.body[p + 4] = document.body[p + 4][1:]
2314 if document.body[p + 4].endswith(">"):
2316 document.body[p + 4] = document.body[p + 4][:-1]
2317 elif layoutname != "Itemize":
2319 document.body[p] = "\\begin_inset Argument 2"
2324 # Helper function for the frame conversion routines
2326 # FIXME: This method currently requires the arguments to be either
2327 # * In one (whole) ERT each: <ERT>[<arg1>]</ERT><ERT><arg2></ERT><ERT>[arg3]</ERT>
2328 # * Altogether in one whole ERT: <ERT>[<arg1>]<arg2>[arg3]</ERT>
2329 # If individual arguments mix ERT and non-ERT or are splitted
2330 # over several ERTs, the parsing fails.
2331 def convert_beamerframeargs(document, i, parbeg):
2334 if document.body[parbeg] != "\\begin_inset ERT":
2336 ertend = find_end_of_inset(document.body, parbeg)
2338 document.warning("Malformed LyX document: missing ERT \\end_inset")
2340 ertcont = parbeg + 5
2341 if document.body[ertcont].startswith("[<"):
2342 # This is a default overlay specification
2344 document.body[ertcont] = document.body[ertcont][2:]
2345 if document.body[ertcont].endswith(">]"):
2347 document.body[ertcont] = document.body[ertcont][:-2]
2348 elif document.body[ertcont].endswith("]"):
2350 tok = document.body[ertcont].find('>][')
2352 subst = [document.body[ertcont][:tok],
2353 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2354 'status collapsed', '', '\\begin_layout Plain Layout',
2355 document.body[ertcont][tok + 3:-1]]
2356 document.body[ertcont : ertcont + 1] = subst
2358 # Convert to ArgInset
2359 document.body[parbeg] = "\\begin_inset Argument 2"
2360 elif document.body[ertcont].startswith("<"):
2361 # This is an overlay specification
2363 document.body[ertcont] = document.body[ertcont][1:]
2364 if document.body[ertcont].endswith(">"):
2366 document.body[ertcont] = document.body[ertcont][:-1]
2367 # Convert to ArgInset
2368 document.body[parbeg] = "\\begin_inset Argument 1"
2369 elif document.body[ertcont].endswith(">]"):
2371 tok = document.body[ertcont].find('>[<')
2373 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2374 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2375 'status collapsed', '', '\\begin_layout Plain Layout',
2376 document.body[ertcont][tok + 3:-2]]
2377 # Convert to ArgInset
2378 document.body[parbeg] = "\\begin_inset Argument 1"
2380 elif document.body[ertcont].endswith("]"):
2382 tok = document.body[ertcont].find('>[<')
2385 tokk = document.body[ertcont].find('>][')
2387 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2388 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2389 'status collapsed', '', '\\begin_layout Plain Layout',
2390 document.body[ertcont][tok + 3:tokk],
2391 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2392 'status collapsed', '', '\\begin_layout Plain Layout',
2393 document.body[ertcont][tokk + 3:-1]]
2396 tokk = document.body[ertcont].find('>[')
2398 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tokk],
2399 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2400 'status collapsed', '', '\\begin_layout Plain Layout',
2401 document.body[ertcont][tokk + 2:-1]]
2403 # Convert to ArgInset
2404 document.body[parbeg] = "\\begin_inset Argument 1"
2405 elif document.body[ertcont].startswith("["):
2406 # This is an ERT option
2408 document.body[ertcont] = document.body[ertcont][1:]
2409 if document.body[ertcont].endswith("]"):
2411 document.body[ertcont] = document.body[ertcont][:-1]
2412 # Convert to ArgInset
2413 document.body[parbeg] = "\\begin_inset Argument 3"
2419 def convert_againframe_args(document):
2420 " Converts beamer AgainFrame to new layout "
2422 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2423 if document.textclass not in beamer_classes:
2428 i = find_token(document.body, "\\begin_layout AgainFrame", i)
2431 parent = get_containing_layout(document.body, i)
2433 document.warning("Wrong parent layout!")
2437 # Convert ERT arguments
2438 # FIXME: See restrictions in convert_beamerframeargs method
2439 ertend = convert_beamerframeargs(document, i, parbeg)
2445 def convert_corollary_args(document):
2446 " Converts beamer corrolary-style ERT arguments native InsetArgs "
2448 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2449 if document.textclass not in beamer_classes:
2452 corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2453 for lay in corollary_layouts:
2456 i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2459 parent = get_containing_layout(document.body, i)
2461 document.warning("Wrong parent layout!")
2465 if document.body[parbeg] == "\\begin_inset ERT":
2466 ertcontfirstline = parbeg + 5
2467 # Find the last ERT in this paragraph (which might also be the first)
2468 lastertbeg = find_token_backwards(document.body, "\\begin_inset ERT", j)
2469 if lastertbeg == -1:
2470 document.warning("Last ERT not found!")
2472 lastertend = find_end_of_inset(document.body, lastertbeg)
2473 if lastertend == -1:
2474 document.warning("End of last ERT not found!")
2476 ertcontlastline = lastertend - 3
2477 if document.body[ertcontfirstline].startswith("<"):
2478 # This is an overlay specification
2480 document.body[ertcontfirstline] = document.body[ertcontfirstline][1:]
2481 if document.body[ertcontlastline].endswith(">"):
2483 document.body[ertcontlastline] = document.body[ertcontlastline][:-1]
2484 if ertcontfirstline < ertcontlastline:
2485 # Multiline ERT. Might contain TeX code. Embrace in ERT.
2486 document.body[ertcontlastline : ertcontlastline + 1] = [
2487 document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
2488 document.body[ertcontfirstline : ertcontfirstline + 1] = [
2489 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
2490 'status collapsed', '', '\\begin_layout Plain Layout',
2491 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
2492 document.body[ertcontfirstline]]
2494 # Convert to ArgInset
2495 document.body[parbeg] = "\\begin_inset Argument 1"
2496 elif document.body[ertcontlastline].endswith("]"):
2498 tok = document.body[ertcontfirstline].find('>[')
2500 if ertcontfirstline < ertcontlastline:
2501 # Multiline ERT. Might contain TeX code. Embrace in ERT.
2502 document.body[ertcontlastline : ertcontlastline + 1] = [
2503 document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
2504 document.body[ertcontfirstline : ertcontfirstline + 1] = [document.body[ertcontfirstline][:tok],
2505 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2506 'status collapsed', '', '\\begin_layout Plain Layout',
2507 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
2508 document.body[ertcontfirstline][tok + 2:-1]]
2510 document.body[ertcontfirstline : ertcontfirstline + 1] = [document.body[ertcontfirstline][:tok],
2511 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2512 'status collapsed', '', '\\begin_layout Plain Layout',
2513 document.body[ertcontfirstline][tok + 2:-1]]
2514 # Convert to ArgInset
2515 document.body[parbeg] = "\\begin_inset Argument 1"
2518 elif document.body[ertcontlastline].startswith("["):
2519 if document.body[ertcontlastline].endswith("]"):
2520 # This is an ERT option
2522 document.body[ertcontlastline] = document.body[ertcontlastline][1:]
2524 document.body[ertcontlastline] = document.body[ertcontlastline][:-1]
2525 # Convert to ArgInset
2526 document.body[parbeg] = "\\begin_inset Argument 2"
2528 convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, True)
2535 def convert_quote_args(document):
2536 " Converts beamer quote style ERT args to native InsetArgs "
2538 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2539 if document.textclass not in beamer_classes:
2542 quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2543 for lay in quote_layouts:
2546 i = find_token(document.body, "\\begin_layout " + lay, i)
2549 parent = get_containing_layout(document.body, i)
2551 document.warning("Wrong parent layout!")
2555 if document.body[parbeg] == "\\begin_inset ERT":
2556 if document.body[i + 6].startswith("<"):
2557 # This is an overlay specification
2559 document.body[i + 6] = document.body[i + 6][1:]
2560 if document.body[i + 6].endswith(">"):
2562 document.body[i + 6] = document.body[i + 6][:-1]
2563 # Convert to ArgInset
2564 document.body[i + 1] = "\\begin_inset Argument 1"
2568 def cleanup_beamerargs(document):
2569 " Clean up empty ERTs (conversion artefacts) "
2571 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2572 if document.textclass not in beamer_classes:
2577 i = find_token(document.body, "\\begin_inset Argument", i)
2580 j = find_end_of_inset(document.body, i)
2582 document.warning("Malformed LyX document: Can't find end of Argument inset")
2586 ertbeg = find_token(document.body, "\\begin_inset ERT", i, j)
2589 ertend = find_end_of_inset(document.body, ertbeg)
2591 document.warning("Malformed LyX document: Can't find end of ERT inset")
2593 stripped = [line for line in document.body[ertbeg : ertend + 1] if line.strip()]
2594 if len(stripped) == 5:
2595 # This is an empty ERT
2596 offset = len(document.body[ertbeg : ertend + 1])
2597 del document.body[ertbeg : ertend + 1]
2604 def revert_beamerargs(document):
2605 " Reverts beamer arguments to old layout "
2607 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2608 if document.textclass not in beamer_classes:
2612 list_layouts = ["Itemize", "Enumerate", "Description"]
2613 headings = ["Part", "Section", "Section*", "Subsection", "Subsection*",
2614 "Subsubsection", "Subsubsection*", "FrameSubtitle", "NoteItem"]
2615 quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2616 corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2617 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2620 i = find_token(document.body, "\\begin_inset Argument", i)
2623 # Find containing paragraph layout
2624 parent = get_containing_layout(document.body, i)
2626 document.warning("Malformed LyX document: Can't find parent paragraph layout")
2631 realparbeg = parent[3]
2632 layoutname = parent[0]
2634 for p in range(parbeg, parend):
2638 if layoutname in headings:
2639 m = rx.match(document.body[p])
2643 # Find containing paragraph layout
2644 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2645 endPlain = find_end_of_layout(document.body, beginPlain)
2646 endInset = find_end_of_inset(document.body, p)
2647 argcontent = document.body[beginPlain + 1 : endPlain]
2649 realparend = realparend - len(document.body[p : endInset + 1])
2651 del document.body[p : endInset + 1]
2652 if layoutname == "FrameSubtitle":
2653 pre = put_cmd_in_ert("\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2654 elif layoutname == "NoteItem":
2655 pre = put_cmd_in_ert("\\note<") + argcontent + put_cmd_in_ert(">[item]")
2656 elif layoutname.endswith('*'):
2657 pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower()[:-1] + "<") + argcontent + put_cmd_in_ert(">*")
2659 pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2660 secarg = find_token(document.body, "\\begin_inset Argument 2", parbeg, parend)
2662 # Find containing paragraph layout
2663 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", secarg)
2664 endPlain = find_end_of_layout(document.body, beginPlain)
2665 endInset = find_end_of_inset(document.body, secarg)
2666 argcontent = document.body[beginPlain + 1 : endPlain]
2668 realparend = realparend - len(document.body[secarg : endInset + 1])
2669 del document.body[secarg : endInset + 1]
2670 pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2671 pre += put_cmd_in_ert("{")
2672 document.body[parbeg] = "\\begin_layout Standard"
2673 document.body[realparbeg : realparbeg] = pre
2674 pe = find_end_of_layout(document.body, parbeg)
2675 post = put_cmd_in_ert("}")
2676 document.body[pe : pe] = post
2677 realparend += len(pre) + len(post)
2678 if layoutname == "AgainFrame":
2679 m = rx.match(document.body[p])
2683 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2684 endPlain = find_end_of_layout(document.body, beginPlain)
2685 endInset = find_end_of_inset(document.body, p)
2686 content = document.body[beginPlain + 1 : endPlain]
2688 realparend = realparend - len(document.body[p : endInset + 1])
2690 del document.body[p : endInset + 1]
2691 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2692 document.body[realparbeg : realparbeg] = subst
2693 if layoutname == "Overprint":
2694 m = rx.match(document.body[p])
2698 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2699 endPlain = find_end_of_layout(document.body, beginPlain)
2700 endInset = find_end_of_inset(document.body, p)
2701 content = document.body[beginPlain + 1 : endPlain]
2703 realparend = realparend - len(document.body[p : endInset + 1])
2705 del document.body[p : endInset + 1]
2706 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2707 document.body[realparbeg : realparbeg] = subst
2708 if layoutname == "OverlayArea":
2709 m = rx.match(document.body[p])
2713 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2714 endPlain = find_end_of_layout(document.body, beginPlain)
2715 endInset = find_end_of_inset(document.body, p)
2716 content = document.body[beginPlain + 1 : endPlain]
2718 realparend = realparend - len(document.body[p : endInset + 1])
2720 del document.body[p : endInset + 1]
2721 subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2722 document.body[realparbeg : realparbeg] = subst
2723 if layoutname in list_layouts:
2724 m = rx.match(document.body[p])
2728 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2729 endPlain = find_end_of_layout(document.body, beginPlain)
2730 endInset = find_end_of_inset(document.body, p)
2731 content = document.body[beginPlain + 1 : endPlain]
2732 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2733 realparend = realparend + len(subst) - len(content)
2734 document.body[beginPlain + 1 : endPlain] = subst
2735 elif argnr == "item:1":
2736 j = find_end_of_inset(document.body, i)
2737 # Find containing paragraph layout
2738 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2739 endPlain = find_end_of_layout(document.body, beginPlain)
2740 content = document.body[beginPlain + 1 : endPlain]
2741 del document.body[i:j+1]
2742 if layoutname == "Description":
2743 # Description only has one (overlay) item arg
2744 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2745 # This must be put after the first space (begin of decription body
2746 # in LyX's arkward description list syntax)
2747 # Try to find that place ...
2748 rxx = re.compile(r'^([^\\ ]+ )(.*)$')
2749 for q in range(parbeg, parend):
2750 m = rxx.match(document.body[q])
2752 # We found it. Now insert the ERT argument just there:
2753 document.body[q : q] = [m.group(1), ''] + subst + ['', m.group(2)]
2756 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2757 document.body[realparbeg : realparbeg] = subst
2758 elif argnr == "item:2":
2759 j = find_end_of_inset(document.body, i)
2760 # Find containing paragraph layout
2761 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2762 endPlain = find_end_of_layout(document.body, beginPlain)
2763 content = document.body[beginPlain + 1 : endPlain]
2764 del document.body[i:j+1]
2765 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2766 document.body[realparbeg : realparbeg] = subst
2767 if layoutname in quote_layouts:
2768 m = rx.match(document.body[p])
2772 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2773 endPlain = find_end_of_layout(document.body, beginPlain)
2774 endInset = find_end_of_inset(document.body, p)
2775 content = document.body[beginPlain + 1 : endPlain]
2777 realparend = realparend - len(document.body[p : endInset + 1])
2779 del document.body[p : endInset + 1]
2780 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2781 document.body[realparbeg : realparbeg] = subst
2782 if layoutname in corollary_layouts:
2783 m = rx.match(document.body[p])
2787 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2788 endPlain = find_end_of_layout(document.body, beginPlain)
2789 endInset = find_end_of_inset(document.body, p)
2790 content = document.body[beginPlain + 1 : endPlain]
2792 realparend = realparend - len(document.body[p : endInset + 1])
2794 del document.body[p : endInset + 1]
2795 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2796 document.body[realparbeg : realparbeg] = subst
2801 def revert_beamerargs2(document):
2802 " Reverts beamer arguments to old layout, step 2 "
2804 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2805 if document.textclass not in beamer_classes:
2809 shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2810 corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2811 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2814 i = find_token(document.body, "\\begin_inset Argument", i)
2817 # Find containing paragraph layout
2818 parent = get_containing_layout(document.body, i)
2820 document.warning("Malformed LyX document: Can't find parent paragraph layout")
2825 realparbeg = parent[3]
2826 layoutname = parent[0]
2828 for p in range(parbeg, parend):
2832 if layoutname in shifted_layouts:
2833 m = rx.match(document.body[p])
2837 document.body[p] = "\\begin_inset Argument 1"
2838 if layoutname in corollary_layouts:
2839 m = rx.match(document.body[p])
2843 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2844 endPlain = find_end_of_layout(document.body, beginPlain)
2845 endInset = find_end_of_inset(document.body, p)
2846 content = document.body[beginPlain + 1 : endPlain]
2848 realparend = realparend - len(document.body[p : endInset + 1])
2850 del document.body[p : endInset + 1]
2851 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2852 document.body[realparbeg : realparbeg] = subst
2853 if layoutname == "OverlayArea":
2854 m = rx.match(document.body[p])
2858 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2859 endPlain = find_end_of_layout(document.body, beginPlain)
2860 endInset = find_end_of_inset(document.body, p)
2861 content = document.body[beginPlain + 1 : endPlain]
2863 realparend = realparend - len(document.body[p : endInset + 1])
2865 del document.body[p : endInset + 1]
2866 subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2867 document.body[realparbeg : realparbeg] = subst
2868 if layoutname == "AgainFrame":
2869 m = rx.match(document.body[p])
2873 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2874 endPlain = find_end_of_layout(document.body, beginPlain)
2875 endInset = find_end_of_inset(document.body, p)
2876 content = document.body[beginPlain + 1 : endPlain]
2878 realparend = realparend - len(document.body[p : endInset + 1])
2880 del document.body[p : endInset + 1]
2881 subst = put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
2882 document.body[realparbeg : realparbeg] = subst
2886 def revert_beamerargs3(document):
2887 " Reverts beamer arguments to old layout, step 3 "
2889 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2890 if document.textclass not in beamer_classes:
2893 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2896 i = find_token(document.body, "\\begin_inset Argument", i)
2899 # Find containing paragraph layout
2900 parent = get_containing_layout(document.body, i)
2902 document.warning("Malformed LyX document: Can't find parent paragraph layout")
2907 realparbeg = parent[3]
2908 layoutname = parent[0]
2910 for p in range(parbeg, parend):
2914 if layoutname == "AgainFrame":
2915 m = rx.match(document.body[p])
2919 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2920 endPlain = find_end_of_layout(document.body, beginPlain)
2921 endInset = find_end_of_inset(document.body, p)
2922 content = document.body[beginPlain + 1 : endPlain]
2924 realparend = realparend - len(document.body[p : endInset + 1])
2926 del document.body[p : endInset + 1]
2927 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2928 document.body[realparbeg : realparbeg] = subst
2932 def revert_beamerflex(document):
2933 " Reverts beamer Flex insets "
2935 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2936 if document.textclass not in beamer_classes:
2939 new_flexes = {"Bold" : "\\textbf", "Emphasize" : "\\emph", "Only" : "\\only",
2940 "Uncover" : "\\uncover", "Visible" : "\\visible",
2941 "Invisible" : "\\invisible", "Alternative" : "\\alt",
2942 "Beamer_Note" : "\\note"}
2943 old_flexes = {"Alert" : "\\alert", "Structure" : "\\structure"}
2944 rx = re.compile(r'^\\begin_inset Flex (.+)$')
2948 i = find_token(document.body, "\\begin_inset Flex", i)
2951 m = rx.match(document.body[i])
2953 flextype = m.group(1)
2954 z = find_end_of_inset(document.body, i)
2956 document.warning("Can't find end of Flex " + flextype + " inset.")
2959 if flextype in new_flexes:
2960 pre = put_cmd_in_ert(new_flexes[flextype])
2961 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2963 argend = find_end_of_inset(document.body, arg)
2965 document.warning("Can't find end of Argument!")
2968 # Find containing paragraph layout
2969 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2970 endPlain = find_end_of_layout(document.body, beginPlain)
2971 argcontent = document.body[beginPlain + 1 : endPlain]
2973 z = z - len(document.body[arg : argend + 1])
2975 del document.body[arg : argend + 1]
2976 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2977 arg = find_token(document.body, "\\begin_inset Argument 2", i, z)
2979 argend = find_end_of_inset(document.body, arg)
2981 document.warning("Can't find end of Argument!")
2984 # Find containing paragraph layout
2985 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2986 endPlain = find_end_of_layout(document.body, beginPlain)
2987 argcontent = document.body[beginPlain + 1 : endPlain]
2989 z = z - len(document.body[arg : argend + 1])
2991 del document.body[arg : argend + 1]
2992 if flextype == "Alternative":
2993 pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
2995 pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2996 pre += put_cmd_in_ert("{")
2997 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2998 endPlain = find_end_of_layout(document.body, beginPlain)
3000 z = z - len(document.body[i : beginPlain + 1])
3002 document.body[i : beginPlain + 1] = pre
3003 post = put_cmd_in_ert("}")
3004 document.body[z - 2 : z + 1] = post
3005 elif flextype in old_flexes:
3006 pre = put_cmd_in_ert(old_flexes[flextype])
3007 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
3011 argend = find_end_of_inset(document.body, arg)
3013 document.warning("Can't find end of Argument!")
3016 # Find containing paragraph layout
3017 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3018 endPlain = find_end_of_layout(document.body, beginPlain)
3019 argcontent = document.body[beginPlain + 1 : endPlain]
3021 z = z - len(document.body[arg : argend + 1])
3023 del document.body[arg : argend + 1]
3024 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
3025 pre += put_cmd_in_ert("{")
3026 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
3027 endPlain = find_end_of_layout(document.body, beginPlain)
3029 z = z - len(document.body[i : beginPlain + 1])
3031 document.body[i : beginPlain + 1] = pre
3032 post = put_cmd_in_ert("}")
3033 document.body[z - 2 : z + 1] = post
3038 def revert_beamerblocks(document):
3039 " Reverts beamer block arguments to ERT "
3041 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3042 if document.textclass not in beamer_classes:
3045 blocks = ["Block", "ExampleBlock", "AlertBlock"]
3047 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3050 i = find_token(document.body, "\\begin_inset Argument", i)
3053 # Find containing paragraph layout
3054 parent = get_containing_layout(document.body, i)
3056 document.warning("Malformed LyX document: Can't find parent paragraph layout")
3061 realparbeg = parent[3]
3062 layoutname = parent[0]
3064 for p in range(parbeg, parend):
3068 if layoutname in blocks:
3069 m = rx.match(document.body[p])
3073 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3074 endPlain = find_end_of_layout(document.body, beginPlain)
3075 endInset = find_end_of_inset(document.body, p)
3076 content = document.body[beginPlain + 1 : endPlain]
3078 realparend = realparend - len(document.body[p : endInset + 1])
3080 del document.body[p : endInset + 1]
3081 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3082 document.body[realparbeg : realparbeg] = subst
3084 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3085 endPlain = find_end_of_layout(document.body, beginPlain)
3086 endInset = find_end_of_inset(document.body, p)
3087 content = document.body[beginPlain + 1 : endPlain]
3089 realparend = realparend - len(document.body[p : endInset + 1])
3091 del document.body[p : endInset + 1]
3092 subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3093 document.body[realparbeg : realparbeg] = subst
3098 def convert_beamerblocks(document):
3099 " Converts beamer block ERT args to native InsetArgs "
3101 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3102 if document.textclass not in beamer_classes:
3105 blocks = ["Block", "ExampleBlock", "AlertBlock"]
3109 i = find_token_exact(document.body, "\\begin_layout " + lay, i)
3112 parent = get_containing_layout(document.body, i)
3113 if parent == False or parent[1] != i:
3114 document.warning("Wrong parent layout!")
3121 # If the paragraph starts with a language switch, adjust parbeg
3122 if len(document.body[parbeg]) == 0 and parbeg < parend \
3123 and document.body[parbeg + 1].startswith("\\lang"):
3125 if document.body[parbeg] == "\\begin_inset ERT":
3126 ertcontfirstline = parbeg + 5
3130 # Find the last ERT in this paragraph used for arguments
3131 # (which might also be the first)
3132 lastertbeg = find_token_backwards(document.body, "\\begin_inset ERT", j)
3133 if lastertbeg == -1:
3134 document.warning("Last ERT not found!")
3136 lastertend = find_end_of_inset(document.body, lastertbeg)
3137 if lastertend == -1:
3138 document.warning("End of last ERT not found!")
3140 # Is this ERT really used for an argument?
3141 # Note: This will fail when non-argument ERTs actually use brackets
3143 regexp = re.compile(r'.*[>\]\}]', re.IGNORECASE)
3144 cbracket = find_re(document.body, regexp, lastertbeg, lastertend)
3147 if lastertbeg == parbeg:
3150 if lastertbeg == -1 or lastertend == -1:
3152 ertcontlastline = lastertend - 3
3154 if document.body[ertcontfirstline].lstrip().startswith("<"):
3155 # This is an overlay specification
3157 document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3158 if document.body[ertcontlastline].rstrip().endswith(">"):
3160 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3161 # Convert to ArgInset
3162 document.body[parbeg] = "\\begin_inset Argument 1"
3163 elif document.body[ertcontlastline].rstrip().endswith("}"):
3165 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3167 ertcontdivline = ertcontfirstline
3168 tok = document.body[ertcontdivline].find('>{')
3170 regexp = re.compile(r'.*>\{', re.IGNORECASE)
3171 ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3172 tok = document.body[ertcontdivline].find('>{')
3174 if ertcontfirstline < ertcontlastline:
3175 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3176 document.body[ertcontlastline : ertcontlastline + 1] = [
3177 document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3178 if ertcontdivline == ertcontfirstline:
3179 document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3180 '\\end_layout', '', '\\end_inset', '',
3181 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3182 'status collapsed', '', '\\begin_layout Plain Layout',
3183 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3184 document.body[ertcontdivline][tok + 2:]]
3186 document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3187 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3188 'status collapsed', '', '\\begin_layout Plain Layout',
3189 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3190 document.body[ertcontdivline][tok + 2:]]
3192 document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3193 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3194 'status collapsed', '', '\\begin_layout Plain Layout',
3195 document.body[ertcontdivline][tok + 2:]]
3197 # check if have delimiters in two different ERTs
3198 tok = document.body[ertcontdivline].find('>')
3200 regexp = re.compile(r'.*>', re.IGNORECASE)
3201 ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3202 tok = document.body[ertcontdivline].find('>')
3204 tokk = document.body[ertcontdivline].find('{')
3206 regexp = re.compile(r'.*\{', re.IGNORECASE)
3207 ertcontdivlinetwo = find_re(document.body, regexp, ertcontfirstline, lastertend)
3208 tokk = document.body[ertcontdivlinetwo].find('{')
3210 if ertcontfirstline < ertcontlastline:
3211 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3212 document.body[ertcontlastline : ertcontlastline + 1] = [
3213 document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3214 document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3215 '\\end_layout', '', '\\end_inset', '', '\\end_layout', '',
3216 '\\end_inset', '', '', '\\begin_inset Argument 2',
3217 'status collapsed', '', '\\begin_layout Plain Layout',
3218 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3219 document.body[ertcontdivlinetwo][tokk + 1:]]
3221 document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3222 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3223 'status collapsed', '', '\\begin_layout Plain Layout',
3224 document.body[ertcontdivlinetwo][tokk + 1:]]
3225 # Convert to ArgInset
3226 if ertcontfirstline < ertcontlastline:
3227 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3228 document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 1',
3229 'status collapsed', '', '\\begin_layout Plain Layout',
3230 '\\begin_inset ERT', '']
3232 document.body[parbeg] = "\\begin_inset Argument 1"
3233 elif document.body[ertcontfirstline].lstrip().startswith("{"):
3234 # This is the block title
3235 if document.body[ertcontlastline].rstrip().endswith("}"):
3236 # strip off the braces
3237 document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3238 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3239 if ertcontfirstline < ertcontlastline:
3240 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3241 document.body[parend : parend + 1] = [
3242 document.body[parend], '\\end_inset', '', '\\end_layout']
3243 document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 2',
3244 'status collapsed', '', '\\begin_layout Plain Layout',
3245 '\\begin_inset ERT', '']
3247 # Convert to ArgInset
3248 document.body[parbeg] = "\\begin_inset Argument 2"
3249 # the overlay argument can also follow the title, so ...
3250 elif document.body[ertcontlastline].rstrip().endswith(">"):
3252 document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3254 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3256 ertcontdivline = ertcontfirstline
3257 tok = document.body[ertcontdivline].find('}<')
3259 regexp = re.compile(r'.*\}<', re.IGNORECASE)
3260 ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3261 tok = document.body[ertcontdivline].find('}<')
3263 if ertcontfirstline < ertcontlastline:
3264 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3265 document.body[ertcontlastline : ertcontlastline + 1] = [
3266 document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3267 if ertcontdivline == ertcontfirstline:
3268 document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3269 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3270 'status collapsed', '', '\\begin_layout Plain Layout',
3271 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3272 document.body[ertcontdivline][tok + 2:]]
3274 document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3275 '\\end_layout', '', '\\end_inset', '',
3276 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3277 'status collapsed', '', '\\begin_layout Plain Layout',
3278 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3279 document.body[ertcontdivline][tok + 2:]]
3281 document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3282 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3283 'status collapsed', '', '\\begin_layout Plain Layout',
3284 document.body[ertcontdivline][tok + 2:]]
3286 # check if have delimiters in two different ERTs
3287 tok = document.body[ertcontdivline].find('}')
3289 regexp = re.compile(r'.*\}', re.IGNORECASE)
3290 ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3291 tok = document.body[ertcontdivline].find('}')
3293 tokk = document.body[ertcontdivline].find('<')
3295 regexp = re.compile(r'.*<', re.IGNORECASE)
3296 ertcontdivlinetwo = find_re(document.body, regexp, ertcontfirstline, lastertend)
3297 tokk = document.body[ertcontdivlinetwo].find('<')
3299 if ertcontfirstline < ertcontlastline:
3300 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3301 document.body[ertcontlastline : ertcontlastline + 1] = [
3302 document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3303 document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3304 '\\end_layout', '', '\\end_inset', '', '\\end_layout', '',
3305 '\\end_inset', '', '', '\\begin_inset Argument 1',
3306 'status collapsed', '', '\\begin_layout Plain Layout',
3307 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3308 document.body[ertcontdivlinetwo][tokk + 1:]]
3310 document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3311 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3312 'status collapsed', '', '\\begin_layout Plain Layout',
3313 document.body[ertcontdivlinetwo][tokk + 1:]]
3314 # Convert to ArgInset
3315 if ertcontfirstline < ertcontlastline:
3316 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3317 document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 2',
3318 'status collapsed', '', '\\begin_layout Plain Layout',
3319 '\\begin_inset ERT', '']
3321 document.body[parbeg] = "\\begin_inset Argument 2"
3322 elif count_pars_in_inset(document.body, ertcontfirstline) > 1:
3323 # Multipar ERT. Skip this.
3326 # ERT has contents after the closing bracket. We cannot convert this.
3327 # convert_TeX_brace_to_Argument cannot either.
3328 #convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, False)
3332 j = find_end_of_layout(document.body, i)
3334 document.warning("end of layout not found!")
3335 k = find_token(document.body, "\\begin_inset Argument", i, j)
3337 document.warning("InsetArgument not found!")
3339 l = find_end_of_inset(document.body, k)
3340 m = find_token(document.body, "\\begin_inset ERT", l, j)
3343 ertcontfirstline = m + 5
3348 def convert_overprint(document):
3349 " Convert old beamer overprint layouts to ERT "
3351 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3352 if document.textclass not in beamer_classes:
3357 i = find_token(document.body, "\\begin_layout Overprint", i)
3360 # Find end of sequence
3361 j = find_end_of_sequence(document.body, i)
3363 document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
3367 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
3369 if document.body[j] == "\\end_deeper":
3370 esubst = ["", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
3372 esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
3373 endseq = endseq + len(esubst) - len(document.body[j : j])
3374 document.body[j : j] = esubst
3375 argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3377 argend = find_end_of_layout(document.body, argbeg)
3379 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3382 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3383 endPlain = find_end_of_layout(document.body, beginPlain)
3384 content = document.body[beginPlain + 1 : endPlain]
3386 endseq = endseq - len(document.body[argbeg : argend + 1])
3388 del document.body[argbeg : argend + 1]
3389 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3391 endseq = endseq - len(document.body[i : i])
3392 document.body[i : i] = subst + ["\\end_layout"]
3393 endseq += len(subst)
3395 for p in range(i, endseq):
3396 if document.body[p] == "\\begin_layout Overprint":
3397 document.body[p] = "\\begin_layout Standard"
3402 def revert_overprint(document):
3403 " Revert old beamer overprint layouts to ERT "
3405 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3406 if document.textclass not in beamer_classes:
3411 i = find_token(document.body, "\\begin_layout Overprint", i)
3414 # Find end of sequence
3415 j = find_end_of_sequence(document.body, i)
3417 document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
3421 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
3422 esubst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}")
3423 endseq = endseq + len(esubst) - len(document.body[j : j])
3424 if document.body[j] == "\\end_deeper":
3425 document.body[j : j] = [""] + esubst + ["", "\\end_layout"]
3427 document.body[j : j] = ["\\end_layout", ""] + esubst
3430 if document.body[r] == "\\begin_deeper":
3431 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3433 document.body[r] = ""
3434 document.body[s] = ""
3438 argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3440 # Is this really our argument?
3441 nested = find_token(document.body, "\\begin_deeper", i, argbeg)
3443 argend = find_end_of_inset(document.body, argbeg)
3445 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3448 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3449 endPlain = find_end_of_layout(document.body, beginPlain)
3450 content = document.body[beginPlain + 1 : endPlain]
3452 endseq = endseq - len(document.body[argbeg : argend])
3454 del document.body[argbeg : argend + 1]
3455 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3457 endseq = endseq - len(document.body[i : i])
3458 document.body[i : i] = subst + ["\\end_layout"]
3459 endseq += len(subst)
3465 if document.body[p] == "\\begin_layout Overprint":
3466 q = find_end_of_layout(document.body, p)
3468 document.warning("Malformed LyX document. Cannot find end of Overprint layout!")
3471 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\onslide")
3472 argbeg = find_token(document.body, "\\begin_inset Argument item:1", p, q)
3474 argend = find_end_of_inset(document.body, argbeg)
3476 document.warning("Malformed LyX document. Cannot find end of Overprint item argument!")
3479 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3480 endPlain = find_end_of_layout(document.body, beginPlain)
3481 content = document.body[beginPlain + 1 : endPlain]
3483 endseq = endseq - len(document.body[argbeg : argend + 1])
3485 del document.body[argbeg : argend + 1]
3486 subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3487 endseq = endseq - len(document.body[p : p + 1]) + len(subst)
3488 document.body[p : p + 1] = subst
3494 def revert_frametitle(document):
3495 " Reverts beamer frametitle layout to ERT "
3497 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3498 if document.textclass not in beamer_classes:
3501 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3504 i = find_token(document.body, "\\begin_layout FrameTitle", i)
3507 j = find_end_of_layout(document.body, i)
3509 document.warning("Malformed LyX document: Can't find end of FrameTitle layout")
3513 document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
3514 endlay += len(put_cmd_in_ert("}"))
3515 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\frametitle")
3516 for p in range(i, j):
3519 m = rx.match(document.body[p])
3523 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3524 endPlain = find_end_of_layout(document.body, beginPlain)
3525 endInset = find_end_of_inset(document.body, p)
3526 content = document.body[beginPlain + 1 : endPlain]
3528 endlay = endlay - len(document.body[p : endInset + 1])
3530 del document.body[p : endInset + 1]
3531 subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3533 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3534 endPlain = find_end_of_layout(document.body, beginPlain)
3535 endInset = find_end_of_inset(document.body, p)
3536 content = document.body[beginPlain + 1 : endPlain]
3538 endlay = endlay - len(document.body[p : endInset + 1])
3540 del document.body[p : endInset + 1]
3541 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3543 subst += put_cmd_in_ert("{")
3544 document.body[i : i + 1] = subst
3548 def convert_epigraph(document):
3549 " Converts memoir epigraph to new syntax "
3551 if document.textclass != "memoir":
3556 i = find_token(document.body, "\\begin_layout Epigraph", i)
3559 j = find_end_of_layout(document.body, i)
3561 document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3566 ert = find_token(document.body, "\\begin_inset ERT", i, j)
3568 endInset = find_end_of_inset(document.body, ert)
3569 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", ert)
3570 endPlain = find_end_of_layout(document.body, beginPlain)
3571 ertcont = beginPlain + 2
3572 if document.body[ertcont] == "}{":
3574 # Convert to ArgInset
3575 endlay = endlay - 2 * len(document.body[j])
3576 begsubst = ['\\begin_inset Argument post:1', 'status collapsed', '',
3577 '\\begin_layout Plain Layout']
3578 endsubst = ['\\end_layout', '', '\\end_inset', '', document.body[j]]
3579 document.body[j : j + 1] = endsubst
3580 document.body[endInset + 1 : endInset + 1] = begsubst
3582 endlay += len(begsubst) + len(endsubst)
3583 endlay = endlay - len(document.body[ert : endInset + 1])
3584 del document.body[ert : endInset + 1]
3589 def revert_epigraph(document):
3590 " Reverts memoir epigraph argument to ERT "
3592 if document.textclass != "memoir":
3597 i = find_token(document.body, "\\begin_layout Epigraph", i)
3600 j = find_end_of_layout(document.body, i)
3602 document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3607 p = find_token(document.body, "\\begin_layout Argument post:1", i, j)
3609 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3610 endPlain = find_end_of_layout(document.body, beginPlain)
3611 endInset = find_end_of_inset(document.body, p)
3612 content = document.body[beginPlain + 1 : endPlain]
3614 endlay = endlay - len(document.body[p : endInset + 1])
3616 del document.body[p : endInset + 1]
3617 subst += put_cmd_in_ert("}{") + content
3619 subst += put_cmd_in_ert("}{")
3621 document.body[j : j] = subst + document.body[j : j]
3625 def convert_captioninsets(document):
3626 " Converts caption insets to new syntax "
3630 i = find_token(document.body, "\\begin_inset Caption", i)
3633 document.body[i] = "\\begin_inset Caption Standard"
3637 def revert_captioninsets(document):
3638 " Reverts caption insets to old syntax "
3642 i = find_token(document.body, "\\begin_inset Caption Standard", i)
3645 document.body[i] = "\\begin_inset Caption"
3649 def convert_captionlayouts(document):
3650 " Convert caption layouts to caption insets. "
3653 "Captionabove": "Above",
3654 "Captionbelow": "Below",
3655 "FigCaption" : "FigCaption",
3656 "Table_Caption" : "Table",
3657 "CenteredCaption" : "Centered",
3658 "Bicaption" : "Bicaption",
3663 i = find_token(document.body, "\\begin_layout", i)
3666 val = get_value(document.body, "\\begin_layout", i)
3667 if val in list(caption_dict.keys()):
3668 j = find_end_of_layout(document.body, i)
3670 document.warning("Malformed LyX document: Missing `\\end_layout'.")
3673 document.body[j:j] = ["\\end_layout", "", "\\end_inset", "", ""]
3674 document.body[i:i+1] = ["\\begin_layout %s" % document.default_layout,
3675 "\\begin_inset Caption %s" % caption_dict[val], "",
3676 "\\begin_layout %s" % document.default_layout]
3680 def revert_captionlayouts(document):
3681 " Revert caption insets to caption layouts. "
3684 "Above" : "Captionabove",
3685 "Below" : "Captionbelow",
3686 "FigCaption" : "FigCaption",
3687 "Table" : "Table_Caption",
3688 "Centered" : "CenteredCaption",
3689 "Bicaption" : "Bicaption",
3693 rx = re.compile(r'^\\begin_inset Caption (\S+)$')
3695 i = find_token(document.body, "\\begin_inset Caption", i)
3699 m = rx.match(document.body[i])
3703 if val not in list(caption_dict.keys()):
3707 # We either need to delete the previous \begin_layout line, or we
3708 # need to end the previous layout if this inset is not in the first
3709 # position of the paragraph.
3710 layout_before = find_token_backwards(document.body, "\\begin_layout", i)
3711 if layout_before == -1:
3712 document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3714 layout_line = document.body[layout_before]
3715 del_layout_before = True
3716 l = layout_before + 1
3718 if document.body[l] != "":
3719 del_layout_before = False
3722 if del_layout_before:
3723 del document.body[layout_before:i]
3726 document.body[i:i] = ["\\end_layout", ""]
3729 # Find start of layout in the inset and end of inset
3730 j = find_token(document.body, "\\begin_layout", i)
3732 document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3734 k = find_end_of_inset(document.body, i)
3736 document.warning("Malformed LyX document: Missing `\\end_inset'.")
3739 # We either need to delete the following \end_layout line, or we need
3740 # to restart the old layout if this inset is not at the paragraph end.
3741 layout_after = find_token(document.body, "\\end_layout", k)
3742 if layout_after == -1:
3743 document.warning("Malformed LyX document: Missing `\\end_layout'.")
3745 del_layout_after = True
3747 while l < layout_after:
3748 if document.body[l] != "":
3749 del_layout_after = False
3752 if del_layout_after:
3753 del document.body[k+1:layout_after+1]
3755 document.body[k+1:k+1] = [layout_line, ""]
3757 # delete \begin_layout and \end_inset and replace \begin_inset with
3758 # "\begin_layout XXX". This works because we can only have one
3759 # paragraph in the caption inset: The old \end_layout will be recycled.
3760 del document.body[k]
3761 if document.body[k] == "":
3762 del document.body[k]
3763 del document.body[j]
3764 if document.body[j] == "":
3765 del document.body[j]
3766 document.body[i] = "\\begin_layout %s" % caption_dict[val]
3767 if document.body[i+1] == "":
3768 del document.body[i+1]
3772 def revert_fragileframe(document):
3773 " Reverts beamer FragileFrame layout to ERT "
3775 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3776 if document.textclass not in beamer_classes:
3781 i = find_token(document.body, "\\begin_layout FragileFrame", i)
3784 # Find end of sequence
3785 j = find_end_of_sequence(document.body, i)
3787 document.warning("Malformed LyX document. Cannot find end of FragileFrame sequence!")
3791 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{frame}")
3792 esubst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\end{frame}")
3793 endseq = endseq + len(esubst) - len(document.body[j : j])
3794 if document.body[j] == "\\end_deeper":
3795 document.body[j : j] = [""] + esubst + ["", "\\end_layout"]
3797 document.body[j : j] = esubst
3798 for q in range(i, j):
3799 if document.body[q] == "\\begin_layout FragileFrame":
3800 document.body[q] = "\\begin_layout %s" % document.default_layout
3803 if document.body[r] == "\\begin_deeper":
3804 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3806 document.body[r] = ""
3807 document.body[s] = ""
3811 for p in range(1, 5):
3812 arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, j)
3815 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3816 endPlain = find_end_of_layout(document.body, beginPlain)
3817 endInset = find_end_of_inset(document.body, arg)
3818 content = document.body[beginPlain + 1 : endPlain]
3820 j = j - len(document.body[arg : endInset + 1])
3822 del document.body[arg : endInset + 1]
3823 subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3825 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3826 endPlain = find_end_of_layout(document.body, beginPlain)
3827 endInset = find_end_of_inset(document.body, arg)
3828 content = document.body[beginPlain + 1 : endPlain]
3830 j = j - len(document.body[arg : endInset + 1])
3832 del document.body[arg : endInset + 1]
3833 subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3835 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3836 endPlain = find_end_of_layout(document.body, beginPlain)
3837 endInset = find_end_of_inset(document.body, arg)
3838 content = document.body[beginPlain + 1 : endPlain]
3840 j = j - len(document.body[arg : endInset + 1])
3842 del document.body[arg : endInset + 1]
3843 subst += put_cmd_in_ert("[fragile,") + content + put_cmd_in_ert("]")
3845 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3846 endPlain = find_end_of_layout(document.body, beginPlain)
3847 endInset = find_end_of_inset(document.body, arg)
3848 content = document.body[beginPlain + 1 : endPlain]
3850 j = j - len(document.body[arg : endInset + 1])
3852 del document.body[arg : endInset + 1]
3853 subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3855 subst += put_cmd_in_ert("[fragile]")
3857 document.body[i : i + 1] = subst
3861 def revert_newframes(document):
3862 " Reverts beamer Frame and PlainFrame layouts to old forms "
3864 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3865 if document.textclass not in beamer_classes:
3869 "Frame" : "BeginFrame",
3870 "PlainFrame" : "BeginPlainFrame",
3873 rx = re.compile(r'^\\begin_layout (\S+)$')
3876 i = find_token(document.body, "\\begin_layout", i)
3880 m = rx.match(document.body[i])
3884 if val not in list(frame_dict.keys()):
3887 # Find end of sequence
3888 j = find_end_of_sequence(document.body, i)
3890 document.warning("Malformed LyX document. Cannot find end of Frame sequence!")
3894 subst = ["\\begin_layout %s" % frame_dict[val]]
3895 esubst = ["", "\\begin_layout EndFrame", "", "\\end_layout"]
3896 endseq = endseq + len(esubst) - len(document.body[j : j])
3897 if document.body[j] == "\\end_deeper":
3898 document.body[j : j] = esubst
3900 document.body[j+1 : j+1] = esubst
3901 for q in range(i, j):
3902 if document.body[q] == "\\begin_layout %s" % val:
3903 document.body[q] = "\\begin_layout %s" % document.default_layout
3906 if document.body[r] == "\\begin_deeper":
3907 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3909 document.body[r] = ""
3910 document.body[s] = ""
3914 l = find_end_of_layout(document.body, i)
3915 for p in range(1, 5):
3916 arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, l)
3919 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3920 endPlain = find_end_of_layout(document.body, beginPlain)
3921 endInset = find_end_of_inset(document.body, arg)
3922 content = document.body[beginPlain + 1 : endPlain]
3924 l = l - len(document.body[arg : endInset + 1])
3926 del document.body[arg : endInset + 1]
3927 subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3929 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3930 endPlain = find_end_of_layout(document.body, beginPlain)
3931 endInset = find_end_of_inset(document.body, arg)
3932 content = document.body[beginPlain + 1 : endPlain]
3934 l = l - len(document.body[arg : endInset + 1])
3936 del document.body[arg : endInset + 1]
3937 subst += put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
3939 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3940 endPlain = find_end_of_layout(document.body, beginPlain)
3941 endInset = find_end_of_inset(document.body, arg)
3942 content = document.body[beginPlain + 1 : endPlain]
3944 l = l - len(document.body[arg : endInset + 1])
3946 del document.body[arg : endInset + 1]
3947 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3949 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3950 endPlain = find_end_of_layout(document.body, beginPlain)
3951 endInset = find_end_of_inset(document.body, arg)
3952 content = document.body[beginPlain + 1 : endPlain]
3954 l = l - len(document.body[arg : endInset + 1])
3956 del document.body[arg : endInset + 1]
3959 document.body[i : i + 1] = subst
3962 # known encodings that do not change their names (same LyX and LaTeX names)
3963 known_enc_tuple = ("auto", "default", "ansinew", "applemac", "armscii8", "ascii",
3964 "cp437", "cp437de", "cp850", "cp852", "cp855", "cp858", "cp862", "cp865", "cp866",
3965 "cp1250", "cp1251", "cp1252", "cp1255", "cp1256", "cp1257", "koi8-r", "koi8-u",
3966 "pt154", "pt254", "tis620-0", "utf8", "utf8x", "utf8-plain")
3968 def convert_encodings(document):
3969 "Use the LyX names of the encodings instead of the LaTeX names."
3970 LaTeX2LyX_enc_dict = {
3971 "8859-6": "iso8859-6",
3972 "8859-8": "iso8859-8",
3974 "euc": "euc-jp-platex",
3979 "iso88595": "iso8859-5",
3980 "iso-8859-7": "iso8859-7",
3982 "jis": "jis-platex",
3984 "l7xenc": "iso8859-13",
3985 "latin1": "iso8859-1",
3986 "latin2": "iso8859-2",
3987 "latin3": "iso8859-3",
3988 "latin4": "iso8859-4",
3989 "latin5": "iso8859-9",
3990 "latin9": "iso8859-15",
3991 "latin10": "iso8859-16",
3992 "SJIS": "shift-jis",
3993 "sjis": "shift-jis-platex",
3996 i = find_token(document.header, "\\inputencoding" , 0)
3999 val = get_value(document.header, "\\inputencoding", i)
4000 if val in list(LaTeX2LyX_enc_dict.keys()):
4001 document.header[i] = "\\inputencoding %s" % LaTeX2LyX_enc_dict[val]
4002 elif val not in known_enc_tuple:
4003 document.warning("Ignoring unknown input encoding: `%s'" % val)
4006 def revert_encodings(document):
4007 """Revert to using the LaTeX names of the encodings instead of the LyX names.
4008 Also revert utf8-platex to sjis, the language default when using Japanese.
4010 LyX2LaTeX_enc_dict = {
4015 "euc-jp-platex": "euc",
4018 "iso8859-1": "latin1",
4019 "iso8859-2": "latin2",
4020 "iso8859-3": "latin3",
4021 "iso8859-4": "latin4",
4022 "iso8859-5": "iso88595",
4023 "iso8859-6": "8859-6",
4024 "iso8859-7": "iso-8859-7",
4025 "iso8859-8": "8859-8",
4026 "iso8859-9": "latin5",
4027 "iso8859-13": "l7xenc",
4028 "iso8859-15": "latin9",
4029 "iso8859-16": "latin10",
4031 "jis-platex": "jis",
4032 "shift-jis": "SJIS",
4033 "shift-jis-platex": "sjis",
4035 "utf8-platex": "sjis"
4037 i = find_token(document.header, "\\inputencoding" , 0)
4040 val = get_value(document.header, "\\inputencoding", i)
4041 if val in list(LyX2LaTeX_enc_dict.keys()):
4042 document.header[i] = "\\inputencoding %s" % LyX2LaTeX_enc_dict[val]
4043 elif val not in known_enc_tuple:
4044 document.warning("Ignoring unknown input encoding: `%s'" % val)
4047 def revert_IEEEtran_3(document):
4049 Reverts Flex Insets to TeX-code
4051 if document.textclass == "IEEEtran":
4057 h = find_token(document.body, "\\begin_inset Flex Author Mark", h)
4059 endh = find_end_of_inset(document.body, h)
4060 document.body[endh - 2 : endh + 1] = put_cmd_in_ert("}")
4061 document.body[h : h + 4] = put_cmd_in_ert("\\IEEEauthorrefmark{")
4064 i = find_token(document.body, "\\begin_inset Flex Author Name", i)
4066 endi = find_end_of_inset(document.body, i)
4067 document.body[endi - 2 : endi + 1] = put_cmd_in_ert("}")
4068 document.body[i : i + 4] = put_cmd_in_ert("\\IEEEauthorblockN{")
4071 j = find_token(document.body, "\\begin_inset Flex Author Affiliation", j)
4073 endj = find_end_of_inset(document.body, j)
4074 document.body[endj - 2 : endj + 1] = put_cmd_in_ert("}")
4075 document.body[j : j + 4] = put_cmd_in_ert("\\IEEEauthorblockA{")
4077 if i == -1 and j == -1 and h == -1:
4081 def revert_kurier_fonts(document):
4082 " Revert kurier font definition to LaTeX "
4084 i = find_token(document.header, "\\font_math", 0)
4086 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
4087 val = get_value(document.header, "\\font_math", i)
4088 if val == "kurier-math":
4089 add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
4090 "\\usepackage[math]{kurier}\n" \
4091 "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
4092 document.header[i] = "\\font_math auto"
4094 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
4095 kurier_fonts = ["kurier", "kurierc", "kurierl", "kurierlc"]
4096 k = find_token(document.header, "\\font_sans kurier", 0)
4098 sf = get_value(document.header, "\\font_sans", k)
4099 if sf in kurier_fonts:
4100 add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
4101 document.header[k] = "\\font_sans default"
4103 def revert_iwona_fonts(document):
4104 " Revert iwona font definition to LaTeX "
4106 i = find_token(document.header, "\\font_math", 0)
4108 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
4109 val = get_value(document.header, "\\font_math", i)
4110 if val == "iwona-math":
4111 add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
4112 "\\usepackage[math]{iwona}\n" \
4113 "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
4114 document.header[i] = "\\font_math auto"
4116 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
4117 iwona_fonts = ["iwona", "iwonac", "iwonal", "iwonalc"]
4118 k = find_token(document.header, "\\font_sans iwona", 0)
4120 sf = get_value(document.header, "\\font_sans", k)
4121 if sf in iwona_fonts:
4122 add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
4123 document.header[k] = "\\font_sans default"
4126 def revert_new_libertines(document):
4127 " Revert new libertine font definition to LaTeX "
4129 if find_token(document.header, "\\use_non_tex_fonts true", 0) != -1:
4132 i = find_token(document.header, "\\font_typewriter libertine-mono", 0)
4134 preamble = "\\usepackage"
4135 sc = find_token(document.header, "\\font_tt_scale", 0)
4137 scval = get_value(document.header, "\\font_tt_scale", sc)
4139 preamble += "[scale=%f]" % (float(scval) / 100)
4140 document.header[sc] = "\\font_tt_scale 100"
4141 preamble += "{libertineMono-type1}"
4142 add_to_preamble(document, [preamble])
4143 document.header[i] = "\\font_typewriter default"
4145 k = find_token(document.header, "\\font_sans biolinum", 0)
4147 preamble = "\\usepackage"
4149 j = find_token(document.header, "\\font_osf true", 0)
4154 sc = find_token(document.header, "\\font_sf_scale", 0)
4156 scval = get_value(document.header, "\\font_sf_scale", sc)
4158 options += ",scale=%f" % (float(scval) / 100)
4159 document.header[sc] = "\\font_sf_scale 100"
4161 preamble += "[" + options +"]"
4162 preamble += "{biolinum-type1}"
4163 add_to_preamble(document, [preamble])
4164 document.header[k] = "\\font_sans default"
4167 def convert_lyxframes(document):
4168 " Converts old beamer frames to new style "
4170 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
4171 if document.textclass not in beamer_classes:
4174 framebeg = ["BeginFrame", "BeginPlainFrame"]
4175 frameend = ["Frame", "PlainFrame", "EndFrame", "BeginFrame", "BeginPlainFrame", "AgainFrame",
4176 "Section", "Section*", "Subsection", "Subsection*", "Subsubsection", "Subsubsection*"]
4177 for lay in framebeg:
4180 i = find_token_exact(document.body, "\\begin_layout " + lay, i)
4183 parent = get_containing_layout(document.body, i)
4184 if parent == False or parent[1] != i:
4185 document.warning("Wrong parent layout!")
4188 frametype = parent[0]
4192 # Step I: Convert ERT arguments
4193 # FIXME: See restrictions in convert_beamerframeargs method
4194 ertend = convert_beamerframeargs(document, i, parbeg)
4197 # Step II: Now rename the layout and convert the title to an argument
4198 j = find_end_of_layout(document.body, i)
4199 document.body[j : j + 1] = ['\\end_layout', '', '\\end_inset', '', '\\end_layout']
4200 if lay == "BeginFrame":
4201 document.body[i] = "\\begin_layout Frame"
4203 document.body[i] = "\\begin_layout PlainFrame"
4204 document.body[ertend + 1 : ertend + 1] = ['\\begin_inset Argument 4',
4205 'status open', '', '\\begin_layout Plain Layout']
4206 # Step III: find real frame end
4209 inInset = get_containing_inset(document.body, i)
4211 fend = find_token(document.body, "\\begin_layout", jj)
4213 document.warning("Malformed LyX document: No real frame end!")
4215 val = get_value(document.body, "\\begin_layout", fend)
4216 if val not in frameend:
4219 # is this frame nested in an inset (e.g., Note)?
4220 if inInset != False:
4221 # if so, end the frame inside the inset
4222 if inInset[2] < fend:
4224 if val == frametype:
4225 document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
4226 # consider explicit EndFrames between two identical frame types
4227 elif val == "EndFrame":
4228 nextlayout = find_token(document.body, "\\begin_layout", fend + 1)
4229 if nextlayout != -1 and get_value(document.body, "\\begin_layout", nextlayout) == frametype:
4230 document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
4232 document.body[fend : fend] = ['\\end_deeper']
4234 document.body[fend : fend] = ['\\end_deeper']
4235 document.body[j + 1 : j + 1] = ['', '\\begin_deeper']
4240 def remove_endframes(document):
4241 " Remove deprecated beamer endframes "
4243 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
4244 if document.textclass not in beamer_classes:
4249 i = find_token_exact(document.body, "\\begin_layout EndFrame", i)
4252 j = find_end_of_layout(document.body, i)
4254 document.warning("Malformed LyX document: Missing \\end_layout to EndFrame")
4257 del document.body[i : j + 1]
4260 def revert_powerdot_flexes(document):
4261 " Reverts powerdot flex insets "
4263 if document.textclass != "powerdot":
4266 flexes = {"Onslide" : "\\onslide",
4267 "Onslide*" : "\\onslide*",
4268 "Onslide+" : "\\onslide+"}
4269 rx = re.compile(r'^\\begin_inset Flex (.+)$')
4273 i = find_token(document.body, "\\begin_inset Flex", i)
4276 m = rx.match(document.body[i])
4278 flextype = m.group(1)
4279 z = find_end_of_inset(document.body, i)
4281 document.warning("Can't find end of Flex " + flextype + " inset.")
4284 if flextype in flexes:
4285 pre = put_cmd_in_ert(flexes[flextype])
4286 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
4288 argend = find_end_of_inset(document.body, arg)
4290 document.warning("Can't find end of Argument!")
4293 # Find containing paragraph layout
4294 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
4295 endPlain = find_end_of_layout(document.body, beginPlain)
4296 argcontent = document.body[beginPlain + 1 : endPlain]
4298 z = z - len(document.body[arg : argend + 1])
4300 del document.body[arg : argend + 1]
4301 pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
4302 pre += put_cmd_in_ert("{")
4303 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4304 endPlain = find_end_of_layout(document.body, beginPlain)
4306 z = z - len(document.body[i : beginPlain + 1])
4308 document.body[i : beginPlain + 1] = pre
4309 post = put_cmd_in_ert("}")
4310 document.body[z - 2 : z + 1] = post
4314 def revert_powerdot_pause(document):
4315 " Reverts powerdot pause layout to ERT "
4317 if document.textclass != "powerdot":
4322 i = find_token(document.body, "\\begin_layout Pause", i)
4325 j = find_end_of_layout(document.body, i)
4327 document.warning("Malformed LyX document: Can't find end of Pause layout")
4331 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\pause")
4332 for p in range(i, j):
4335 arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
4337 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4338 endPlain = find_end_of_layout(document.body, beginPlain)
4339 endInset = find_end_of_inset(document.body, p)
4340 content = document.body[beginPlain + 1 : endPlain]
4342 endlay = endlay - len(document.body[p : endInset + 1])
4344 del document.body[p : endInset + 1]
4345 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4347 document.body[i : i + 1] = subst
4351 def revert_powerdot_itemargs(document):
4352 " Reverts powerdot item arguments to ERT "
4354 if document.textclass != "powerdot":
4358 list_layouts = ["Itemize", "ItemizeType1", "Enumerate", "EnumerateType1"]
4359 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4362 i = find_token(document.body, "\\begin_inset Argument", i)
4365 # Find containing paragraph layout
4366 parent = get_containing_layout(document.body, i)
4368 document.warning("Malformed LyX document: Can't find parent paragraph layout")
4373 realparbeg = parent[3]
4374 layoutname = parent[0]
4376 for p in range(parbeg, parend):
4380 if layoutname in list_layouts:
4381 m = rx.match(document.body[p])
4384 if argnr == "item:1":
4385 j = find_end_of_inset(document.body, i)
4386 # Find containing paragraph layout
4387 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4388 endPlain = find_end_of_layout(document.body, beginPlain)
4389 content = document.body[beginPlain + 1 : endPlain]
4390 del document.body[i:j+1]
4391 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4392 document.body[realparbeg : realparbeg] = subst
4393 elif argnr == "item:2":
4394 j = find_end_of_inset(document.body, i)
4395 # Find containing paragraph layout
4396 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4397 endPlain = find_end_of_layout(document.body, beginPlain)
4398 content = document.body[beginPlain + 1 : endPlain]
4399 del document.body[i:j+1]
4400 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
4401 document.body[realparbeg : realparbeg] = subst
4406 def revert_powerdot_columns(document):
4407 " Reverts powerdot twocolumn to TeX-code "
4408 if document.textclass != "powerdot":
4411 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4414 i = find_token(document.body, "\\begin_layout Twocolumn", i)
4417 j = find_end_of_layout(document.body, i)
4419 document.warning("Malformed LyX document: Can't find end of Twocolumn layout")
4423 document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
4424 endlay += len(put_cmd_in_ert("}"))
4425 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\twocolumn")
4426 for p in range(i, j):
4429 m = rx.match(document.body[p])
4433 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4434 endPlain = find_end_of_layout(document.body, beginPlain)
4435 endInset = find_end_of_inset(document.body, p)
4436 content = document.body[beginPlain + 1 : endPlain]
4438 endlay = endlay - len(document.body[p : endInset + 1])
4440 del document.body[p : endInset + 1]
4441 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4443 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4444 endPlain = find_end_of_layout(document.body, beginPlain)
4445 endInset = find_end_of_inset(document.body, p)
4446 content = document.body[beginPlain + 1 : endPlain]
4448 endlay = endlay - len(document.body[p : endInset + 1])
4450 del document.body[p : endInset + 1]
4451 subst += put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
4453 subst += put_cmd_in_ert("{")
4454 document.body[i : i + 1] = subst
4458 def revert_mbox_fbox(document):
4459 'Convert revert mbox/fbox boxes to TeX-code'
4462 i = find_token(document.body, "\\begin_inset Box", i)
4465 j = find_token(document.body, "width", i)
4467 document.warning("Malformed LyX document: Can't find box width")
4469 width = get_value(document.body, "width", j)
4470 k = find_end_of_inset(document.body, j)
4472 document.warning("Malformed LyX document: Can't find end of box inset")
4475 BeginLayout = find_token(document.body, "\\begin_layout Plain Layout", j)
4476 EndLayout = find_end_of_layout(document.body, BeginLayout)
4477 # replace if width is ""
4479 document.body[EndLayout:k + 1] = put_cmd_in_ert("}")
4480 if document.body[i] == "\\begin_inset Box Frameless":
4481 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\mbox{")
4482 if document.body[i] == "\\begin_inset Box Boxed":
4483 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\fbox{")
4487 def revert_starred_caption(document):
4488 " Reverts unnumbered longtable caption insets "
4492 i = find_token(document.body, "\\begin_inset Caption LongTableNoNumber", i)
4495 # This is not equivalent, but since the caption inset is a full blown
4496 # text inset a true conversion to ERT is too difficult.
4497 document.body[i] = "\\begin_inset Caption Standard"
4501 def revert_forced_local_layout(document):
4504 i = find_token(document.header, "\\begin_forced_local_layout", i)
4507 j = find_end_of(document.header, i, "\\begin_forced_local_layout", "\\end_forced_local_layout")
4509 # this should not happen
4511 regexp = re.compile(r'\s*forcelocal', re.IGNORECASE)
4512 k = find_re(document.header, regexp, i, j)
4514 del document.header[k]
4516 k = find_re(document.header, regexp, i, j)
4517 k = find_token(document.header, "\\begin_local_layout", 0)
4519 document.header[i] = "\\begin_local_layout"
4520 document.header[j] = "\\end_local_layout"
4522 l = find_end_of(document.header, k, "\\begin_local_layout", "\\end_local_layout")
4524 # this should not happen
4526 lines = document.header[i+1 : j]
4528 document.header[k+1 : k+1] = lines
4529 document.header[i : j ] = []
4531 document.header[i : j ] = []
4532 document.header[k+1 : k+1] = lines
4535 def revert_aa1(document):
4536 " Reverts InsetArguments of aa to TeX-code "
4537 if document.textclass == "aa":
4541 i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4543 revert_Argument_to_TeX_brace(document, i, 0, 1, 4, False, False)
4549 def revert_aa2(document):
4550 " Reverts InsetArguments of aa to TeX-code "
4551 if document.textclass == "aa":
4555 i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4557 document.body[i] = "\\begin_layout Abstract"
4563 def revert_tibetan(document):
4564 "Set the document language for Tibetan to English"
4566 if document.language == "tibetan":
4567 document.language = "english"
4568 i = find_token(document.header, "\\language", 0)
4570 document.header[i] = "\\language english"
4572 while j < len(document.body):
4573 j = find_token(document.body, "\\lang tibetan", j)
4575 document.body[j] = document.body[j].replace("\\lang tibetan", "\\lang english")
4578 j = len(document.body)
4587 # The idea here is that we will have a sequence of chunk paragraphs.
4588 # We want to convert them to paragraphs in one or several chunk insets.
4589 # Individual chunks are terminated by the character @ on the last line.
4590 # This line will be discarded, and following lines are treated as new
4591 # chunks, which go into their own insets.
4592 # The first line of a chunk should look like: <<CONTENT>>=
4593 # We will discard the delimiters, and put the CONTENT into the
4594 # optional argument of the inset, if the CONTENT is non-empty.
4595 def convert_chunks(document):
4596 first_re = re.compile(r'<<(.*)>>=(.*)')
4599 # find start of a block of chunks
4600 i = find_token(document.body, "\\begin_layout Chunk", file_pos)
4606 chunk_started = False
4609 # process the one we just found
4610 j = find_end_of_layout(document.body, i)
4612 document.warning("Malformed LyX documents. Can't find end of Chunk layout!")
4613 # there is no point continuing, as we will run into the same error again.
4615 this_chunk = "".join(document.body[i + 1:j])
4617 # there may be empty lines between chunks
4618 # we just skip them.
4619 if not chunk_started:
4620 if this_chunk != "":
4622 chunk_started = True
4625 contents.append(document.body[i + 1:j])
4627 # look for potential chunk terminator
4628 # on the last line of the chunk paragraph
4629 if document.body[j - 1] == "@":
4632 # look for subsequent chunk paragraph
4633 i = find_token(document.body, "\\begin_layout", j)
4637 if get_value(document.body, "\\begin_layout", i) != "Chunk":
4640 file_pos = end = j + 1
4642 # The last chunk should simply have an "@" in it
4643 # or at least end with "@" (can happen if @ is
4644 # preceded by a newline)
4646 if len(contents) > 0:
4647 lastpar = ''.join(contents[-1])
4648 if not lastpar.endswith("@"):
4649 document.warning("Unexpected chunk content: chunk not terminated by '@'!")
4650 if len(contents) == 0:
4651 # convert empty chunk layouts to Standard
4652 document.body[start] = "\\begin_layout Standard"
4656 # chunk par only contains "@". Just drop it.
4659 # chunk par contains more. Only drop the "@".
4662 # The first line should look like: <<CONTENT>>=
4663 # We want the CONTENT
4664 optarg = ' '.join(contents[0])
4666 # We can already have real chunk content in
4667 # the first par (separated from the options by a newline).
4668 # We collect such stuff to re-insert it later.
4671 match = first_re.search(optarg)
4673 optarg = match.groups()[0]
4674 if match.groups()[1] != "":
4676 for c in contents[0]:
4677 if c.endswith(">>="):
4681 postoptstuff.append(c)
4682 # We have stripped everything. This can be deleted.
4685 newstuff = ['\\begin_layout Standard']
4687 # Maintain paragraph parameters
4688 par_params = ["\\noindent", "\\indent", "\\indent-toggle", "\\leftindent",
4689 "\\start_of_appendix", "\\paragraph_spacing", "\\align",
4690 "\\labelwidthstring"]
4693 if document.body[parms].split(' ', 1)[0] not in par_params:
4695 newstuff.extend([document.body[parms]])
4699 ['\\begin_inset Flex Chunk',
4701 '\\begin_layout Plain Layout', ''])
4703 # If we have a non-empty optional argument, insert it.
4704 if match and optarg != "":
4706 ['\\begin_inset Argument 1',
4708 '\\begin_layout Plain Layout',
4713 # Since we already opened a Plain layout, the first paragraph
4714 # does not need to do that.
4717 # we need to replace newlines with new layouts
4719 started_text = False
4720 for lno in range(0,len(postoptstuff)):
4721 if postoptstuff[lno].startswith("\\begin_inset Newline newline"):
4723 elif start_newline != -1:
4724 if postoptstuff[lno].startswith("\\end_inset"):
4725 # replace that bit, but only if we already have some text
4726 # and we're not at the end except for a blank line
4727 if started_text and \
4728 (lno != len(postoptstuff) - 2 or postoptstuff[-1] != ""):
4729 newstuff.extend(['\\end_layout', '\n', '\\begin_layout Plain Layout', '\n'])
4733 newstuff.extend([postoptstuff[lno]])
4734 newstuff.append('\\end_layout')
4738 newstuff.extend(['', '\\begin_layout Plain Layout', ''])
4742 newstuff.append('\\end_layout')
4744 newstuff.extend(['', '\\end_inset', '', '\\end_layout', ''])
4746 document.body[start:end] = newstuff
4748 file_pos += len(newstuff) - (end - start)
4751 def revert_chunks(document):
4754 i = find_token(document.body, "\\begin_inset Flex Chunk", i)
4758 iend = find_end_of_inset(document.body, i)
4760 document.warning("Can't find end of Chunk!")
4764 # Look for optional argument
4766 ostart = find_token(document.body, "\\begin_inset Argument 1", i, iend)
4768 oend = find_end_of_inset(document.body, ostart)
4769 k = find_token(document.body, "\\begin_layout Plain Layout", ostart, oend)
4771 document.warning("Malformed LyX document: Can't find argument contents!")
4773 m = find_end_of_layout(document.body, k)
4774 optarg = "".join(document.body[k+1:m])
4776 # We now remove the optional argument, so we have something
4777 # uniform on which to work
4778 document.body[ostart : oend + 1] = []
4779 # iend is now invalid
4780 iend = find_end_of_inset(document.body, i)
4782 retval = get_containing_layout(document.body, i)
4784 document.warning("Can't find containing layout for Chunk!")
4787 (lname, lstart, lend, pstart) = retval
4788 # we now want to work through the various paragraphs, and collect their contents
4792 k = find_token(document.body, "\\begin_layout Plain Layout", k, lend)
4795 j = find_end_of_layout(document.body, k)
4797 document.warning("Can't find end of layout inside chunk!")
4799 parlist.append(document.body[k+1:j])
4801 # we now need to wrap all of these paragraphs in chunks
4803 newlines.extend(["\\begin_layout Chunk", "", "<<" + optarg + ">>=", "\\end_layout", ""])
4804 for stuff in parlist:
4805 newlines.extend(["\\begin_layout Chunk"] + stuff + ["\\end_layout", ""])
4806 newlines.extend(["\\begin_layout Chunk", "", "@", "\\end_layout", ""])
4807 # replace old content with new content
4808 document.body[lstart : lend + 1] = newlines
4809 i = lstart + len(newlines)
4816 supported_versions = ["2.1.0","2.1"]
4819 [415, [convert_undertilde]],
4821 [417, [convert_japanese_encodings]],
4822 [418, [convert_justification]],
4824 [420, [convert_biblio_style]],
4825 [421, [convert_longtable_captions]],
4826 [422, [convert_use_packages]],
4827 [423, [convert_use_mathtools]],
4828 [424, [convert_cite_engine_type]],
4829 # No convert_cancel, since cancel will be loaded automatically
4830 # in format 425 without any possibility to switch it off.
4831 # This has been fixed in format 464.
4835 [428, [convert_cell_rotation]],
4836 [429, [convert_table_rotation]],
4837 [430, [convert_listoflistings]],
4838 [431, [convert_use_amssymb]],
4840 [433, [convert_armenian]],
4847 [440, [convert_mathfonts]],
4848 [441, [convert_mdnomath]],
4853 [446, [convert_latexargs]],
4854 [447, [convert_IEEEtran, convert_AASTeX, convert_AGUTeX, convert_IJMP, convert_SIGPLAN, convert_SIGGRAPH, convert_EuropeCV, convert_Initials, convert_ModernCV]],
4855 [448, [convert_literate]],
4858 [451, [convert_beamerargs, convert_againframe_args, convert_corollary_args, convert_quote_args]],
4859 [452, [convert_beamerblocks]],
4860 [453, [convert_use_stmaryrd]],
4861 [454, [convert_overprint]],
4863 [456, [convert_epigraph]],
4864 [457, [convert_use_stackrel]],
4865 [458, [convert_captioninsets, convert_captionlayouts]],
4870 [463, [convert_encodings]],
4871 [464, [convert_use_cancel]],
4872 [465, [convert_lyxframes, remove_endframes]],
4878 [471, [convert_cite_engine_type_default]],
4881 [474, [convert_chunks, cleanup_beamerargs]],
4885 [473, [revert_chunks]],
4886 [472, [revert_tibetan]],
4887 [471, [revert_aa1,revert_aa2]],
4888 [470, [revert_cite_engine_type_default]],
4889 [469, [revert_forced_local_layout]],
4890 [468, [revert_starred_caption]],
4891 [467, [revert_mbox_fbox]],
4892 [466, [revert_iwona_fonts]],
4893 [465, [revert_powerdot_flexes, revert_powerdot_pause, revert_powerdot_itemargs, revert_powerdot_columns]],
4895 [463, [revert_use_cancel]],
4896 [462, [revert_encodings]],
4897 [461, [revert_new_libertines]],
4898 [460, [revert_kurier_fonts]],
4899 [459, [revert_IEEEtran_3]],
4900 [458, [revert_fragileframe, revert_newframes]],
4901 [457, [revert_captioninsets, revert_captionlayouts]],
4902 [456, [revert_use_stackrel]],
4903 [455, [revert_epigraph]],
4904 [454, [revert_frametitle]],
4905 [453, [revert_overprint]],
4906 [452, [revert_use_stmaryrd]],
4907 [451, [revert_beamerblocks]],
4908 [450, [revert_beamerargs, revert_beamerargs2, revert_beamerargs3, revert_beamerflex]],
4909 [449, [revert_garamondx, revert_garamondx_newtxmath]],
4910 [448, [revert_itemargs]],
4911 [447, [revert_literate]],
4912 [446, [revert_IEEEtran, revert_IEEEtran_2, revert_AASTeX, revert_AGUTeX, revert_IJMP, revert_SIGPLAN, revert_SIGGRAPH, revert_EuropeCV, revert_Initials, revert_ModernCV_3, revert_ModernCV_4]],
4913 [445, [revert_latexargs]],
4914 [444, [revert_uop]],
4915 [443, [revert_biolinum]],
4917 [441, [revert_newtxmath]],
4918 [440, [revert_mdnomath]],
4919 [439, [revert_mathfonts]],
4920 [438, [revert_minionpro]],
4921 [437, [revert_ipadeco, revert_ipachar]],
4922 [436, [revert_texgyre]],
4923 [435, [revert_mathdesign]],
4924 [434, [revert_txtt]],
4925 [433, [revert_libertine]],
4926 [432, [revert_armenian]],
4927 [431, [revert_languages, revert_ancientgreek]],
4928 [430, [revert_use_amssymb]],
4929 [429, [revert_listoflistings]],
4930 [428, [revert_table_rotation]],
4931 [427, [revert_cell_rotation]],
4932 [426, [revert_tipa]],
4933 [425, [revert_verbatim]],
4934 [424, [revert_cancel]],
4935 [423, [revert_cite_engine_type]],
4936 [422, [revert_use_mathtools]],
4937 [421, [revert_use_packages]],
4938 [420, [revert_longtable_captions]],
4939 [419, [revert_biblio_style]],
4940 [418, [revert_australian]],
4941 [417, [revert_justification]],
4942 [416, [revert_japanese_encodings]],
4943 [415, [revert_negative_space, revert_math_spaces]],
4944 [414, [revert_undertilde]],
4945 [413, [revert_visible_space]]
4949 if __name__ == "__main__":