1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # Copyright (C) 2011 The LyX team
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 """ Convert files to the file format generated by LyX 2.1"""
25 # Uncomment only what you need to import, please.
27 from parser_tools import count_pars_in_inset, del_complete_lines, del_token, \
28 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, revert_language
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 beginBrace != -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)
231 document.warning("Can't find end of ERT!!")
233 # Note that this only checks for [ or { at the beginning of a line
235 opening = find_token(document.body, "[", lineERT, end_ERT)
237 opening = find_token(document.body, "{", lineERT, end_ERT)
239 lineERT2 = find_token(document.body, "\\begin_inset ERT", end_ERT, end_layout)
241 # argument in a single ERT
242 # strip off the opening bracket
243 document.body[opening] = document.body[opening][1:]
244 ertcontlastline = end_ERT - 3
245 if (opt and document.body[ertcontlastline].endswith("]")) or document.body[ertcontlastline].endswith("}"):
246 # strip off the closing bracket
247 document.body[ertcontlastline] = document.body[ertcontlastline][:-1]
248 end2 = find_token(document.body, "\\end_inset", ertcontlastline)
249 document.body[lineERT : lineERT + 1] = ["\\begin_inset Argument " + str(n)]
251 end_ERT2 = find_end_of_inset(document.body, lineERT2)
253 document.warning("Can't find end of second ERT!!")
256 closing = find_token(document.body, "]", lineERT2, end_ERT2)
258 closing = find_token(document.body, "}", lineERT2, end_ERT2)
259 if closing != -1: # assure that the "}" is in this ERT
260 end2 = find_token(document.body, "\\end_inset", closing)
261 document.body[lineERT2 : end2 + 1] = ["\\end_layout", "", "\\end_inset"]
262 document.body[lineERT : end_ERT + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"]
265 document.warning("Unable to process argument!")
269 ###############################################################################
271 ### Conversion and reversion routines
273 ###############################################################################
275 def revert_visible_space(document):
276 "Revert InsetSpace visible into its ERT counterpart"
279 i = find_token(document.body, "\\begin_inset space \\textvisiblespace{}", i)
282 end = find_end_of_inset(document.body, i)
283 subst = put_cmd_in_ert("\\textvisiblespace{}")
284 document.body[i:end + 1] = subst
287 undertilde_commands = ["utilde"]
288 def convert_undertilde(document):
289 " Load undertilde automatically "
290 i = find_token(document.header, "\\use_mathdots" , 0)
292 i = find_token(document.header, "\\use_mhchem" , 0)
294 i = find_token(document.header, "\\use_esint" , 0)
296 document.warning("Malformed LyX document: Can't find \\use_mathdots.")
298 j = find_token(document.preamble, "\\usepackage{undertilde}", 0)
300 # package was loaded in the preamble, convert this to header setting for round trip
301 document.header.insert(i + 1, "\\use_undertilde 2") # on
302 del document.preamble[j]
306 j = find_token(document.body, '\\begin_inset Formula', j)
309 k = find_end_of_inset(document.body, j)
311 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(j))
314 code = "\n".join(document.body[j:k])
315 for c in undertilde_commands:
316 if code.find("\\%s" % c) != -1:
317 # at least one of the commands was found - need to switch package off
318 document.header.insert(i + 1, "\\use_undertilde 0") # off
321 # no command was found - set to auto (bug 9069)
322 document.header.insert(i + 1, "\\use_undertilde 1") # auto
326 def revert_undertilde(document):
327 " Load undertilde if used in the document "
328 regexp = re.compile(r'(\\use_undertilde)')
329 i = find_re(document.header, regexp, 0)
330 value = "1" # default is auto
332 value = get_value(document.header, "\\use_undertilde" , i).split()[0]
333 del document.header[i]
334 if value == "2": # on
335 add_to_preamble(document, ["\\usepackage{undertilde}"])
336 elif value == "1": # auto
339 i = find_token(document.body, '\\begin_inset Formula', i)
342 j = find_end_of_inset(document.body, i)
344 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
347 code = "\n".join(document.body[i:j])
348 for c in undertilde_commands:
349 if code.find("\\%s" % c) != -1:
350 add_to_preamble(document, ["\\usepackage{undertilde}"])
355 def revert_negative_space(document):
356 "Revert InsetSpace negmedspace and negthickspace into their TeX-code counterparts"
361 i = find_token(document.body, "\\begin_inset space \\negmedspace{}", i)
363 j = find_token(document.body, "\\begin_inset space \\negthickspace{}", j)
365 # load amsmath in the preamble if not already loaded if we are at the end of checking
367 i = find_token(document.header, "\\use_amsmath 2", 0)
369 add_to_preamble(document, ["\\@ifundefined{negthickspace}{\\usepackage{amsmath}}{}"])
373 end = find_end_of_inset(document.body, i)
374 subst = put_cmd_in_ert("\\negmedspace{}")
375 document.body[i:end + 1] = subst
376 j = find_token(document.body, "\\begin_inset space \\negthickspace{}", j)
379 end = find_end_of_inset(document.body, j)
380 subst = put_cmd_in_ert("\\negthickspace{}")
381 document.body[j:end + 1] = subst
385 def revert_math_spaces(document):
386 "Revert formulas with protected custom space and protected hfills to TeX-code"
389 i = find_token(document.body, "\\begin_inset Formula", i)
392 j = document.body[i].find("\\hspace*")
394 end = find_end_of_inset(document.body, i)
395 subst = put_cmd_in_ert(document.body[i][21:])
396 document.body[i:end + 1] = subst
400 def convert_japanese_encodings(document):
401 " Rename the japanese encodings to names understood by platex "
403 "EUC-JP-pLaTeX": "euc",
405 "SJIS-pLaTeX": "sjis"
407 i = find_token(document.header, "\\inputencoding" , 0)
410 val = get_value(document.header, "\\inputencoding", i)
411 if val in list(jap_enc_dict.keys()):
412 document.header[i] = "\\inputencoding %s" % jap_enc_dict[val]
415 def revert_japanese_encodings(document):
416 " Revert the japanese encodings name changes "
418 "euc": "EUC-JP-pLaTeX",
420 "sjis": "SJIS-pLaTeX"
422 i = find_token(document.header, "\\inputencoding" , 0)
425 val = get_value(document.header, "\\inputencoding", i)
426 if val in list(jap_enc_dict.keys()):
427 document.header[i] = "\\inputencoding %s" % jap_enc_dict[val]
430 def convert_justification(document):
431 " Add the \\justification buffer param"
432 i = find_token(document.header, "\\suppress_date" , 0)
434 i = find_token(document.header, "\\paperorientation" , 0)
436 i = find_token(document.header, "\\use_indices" , 0)
438 i = find_token(document.header, "\\use_bibtopic" , 0)
440 document.warning("Malformed LyX document: Missing \\suppress_date.")
442 document.header.insert(i + 1, "\\justification true")
445 def revert_justification(document):
446 " Revert the \\justification buffer param"
447 if not del_token(document.header, '\\justification', 0):
448 document.warning("Malformed LyX document: Missing \\justification.")
451 def revert_australian(document):
452 "Set English language variants Australian and Newzealand to English"
454 if document.language == "australian" or document.language == "newzealand":
455 document.language = "english"
456 i = find_token(document.header, "\\language", 0)
458 document.header[i] = "\\language english"
461 j = find_token(document.body, "\\lang australian", j)
463 j = find_token(document.body, "\\lang newzealand", 0)
467 document.body[j] = document.body[j].replace("\\lang newzealand", "\\lang english")
469 document.body[j] = document.body[j].replace("\\lang australian", "\\lang english")
473 def convert_biblio_style(document):
474 "Add a sensible default for \\biblio_style based on the citation engine."
475 i = find_token(document.header, "\\cite_engine", 0)
477 engine = get_value(document.header, "\\cite_engine", i).split("_")[0]
478 style = {"basic": "plain", "natbib": "plainnat", "jurabib": "jurabib"}
479 document.header.insert(i + 1, "\\biblio_style " + style[engine])
482 def revert_biblio_style(document):
483 "BibTeX insets with default option use the style defined by \\biblio_style."
484 i = find_token(document.header, "\\biblio_style" , 0)
486 document.warning("No \\biblio_style line. Nothing to do.")
489 default_style = get_value(document.header, "\\biblio_style", i)
490 del document.header[i]
492 # We are looking for bibtex insets having the default option
495 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
498 j = find_end_of_inset(document.body, i)
500 document.warning("Malformed LyX document: Can't find end of bibtex inset at line " + str(i))
503 k = find_token(document.body, "options", i, j)
505 options = get_quoted_value(document.body, "options", k)
506 if "default" in options.split(","):
507 document.body[k] = 'options "%s"' \
508 % options.replace("default", default_style)
512 def handle_longtable_captions(document, forward):
515 begin_table = find_token(document.body, '<lyxtabular version=', begin_table)
516 if begin_table == -1:
518 end_table = find_end_of(document.body, begin_table, '<lyxtabular', '</lyxtabular>')
520 document.warning("Malformed LyX document: Could not find end of table.")
523 fline = find_token(document.body, "<features", begin_table, end_table)
525 document.warning("Can't find features for inset at line " + str(begin_table))
528 p = document.body[fline].find("islongtable")
533 numrows = get_option_value(document.body[begin_table], "rows")
535 numrows = int(numrows)
537 document.warning(document.body[begin_table])
538 document.warning("Unable to determine rows!")
539 begin_table = end_table
541 begin_row = begin_table
542 for row in range(numrows):
543 begin_row = find_token(document.body, '<row', begin_row, end_table)
545 document.warning("Can't find row " + str(row + 1))
547 end_row = find_end_of(document.body, begin_row, '<row', '</row>')
549 document.warning("Can't find end of row " + str(row + 1))
552 if (get_option_value(document.body[begin_row], 'caption') == 'true' and
553 get_option_value(document.body[begin_row], 'endfirsthead') != 'true' and
554 get_option_value(document.body[begin_row], 'endhead') != 'true' and
555 get_option_value(document.body[begin_row], 'endfoot') != 'true' and
556 get_option_value(document.body[begin_row], 'endlastfoot') != 'true'):
557 document.body[begin_row] = set_option_value(document.body[begin_row], 'caption', 'true", endfirsthead="true')
558 elif get_option_value(document.body[begin_row], 'caption') == 'true':
559 if get_option_value(document.body[begin_row], 'endhead') == 'true':
560 document.body[begin_row] = set_option_value(document.body[begin_row], 'endhead', 'false')
561 if get_option_value(document.body[begin_row], 'endfoot') == 'true':
562 document.body[begin_row] = set_option_value(document.body[begin_row], 'endfoot', 'false')
563 if get_option_value(document.body[begin_row], 'endlastfoot') == 'true':
564 document.body[begin_row] = set_option_value(document.body[begin_row], 'endlastfoot', 'false')
566 # since there could be a tabular inside this one, we
567 # cannot jump to end.
571 def convert_longtable_captions(document):
572 "Add a firsthead flag to caption rows"
573 handle_longtable_captions(document, True)
576 def revert_longtable_captions(document):
577 "remove head/foot flag from caption rows"
578 handle_longtable_captions(document, False)
581 def convert_use_packages(document):
582 "use_xxx yyy => use_package xxx yyy"
583 packages = ["amsmath", "esint", "mathdots", "mhchem", "undertilde"]
585 i = find_token(document.header, "\\use_%s" % p, 0)
587 value = get_value(document.header, "\\use_%s" % p, i)
588 document.header[i] = "\\use_package %s %s" % (p, value)
591 def revert_use_packages(document):
592 "use_package xxx yyy => use_xxx yyy"
593 packages = ["amsmath", "esint", "mhchem", "mathdots", "undertilde"]
594 # the order is arbitrary for the use_package version, and not all packages need to be given.
595 # Ensure a complete list and correct order (important for older LyX versions and especially lyx2lyx)
596 # first loop: find line with first package
599 regexp = re.compile(r'(\\use_package\s+%s)' % p)
600 i = find_re(document.header, regexp, 0)
601 if i != -1 and (j < 0 or i < j):
603 # second loop: replace or insert packages in front of all existing ones
605 regexp = re.compile(r'(\\use_package\s+%s)' % p)
606 i = find_re(document.header, regexp, 0)
608 value = get_value(document.header, "\\use_package %s" % p, i).split()[1]
609 del document.header[i]
610 document.header.insert(j, "\\use_%s %s" % (p, value))
612 document.header.insert(j, "\\use_%s 1" % p)
616 def convert_use_package(document, pkg, commands, oldauto):
617 # oldauto defines how the version we are converting from behaves:
618 # if it is true, the old version uses the package automatically.
619 # if it is false, the old version never uses the package.
620 i = find_token(document.header, "\\use_package")
622 document.warning("Malformed LyX document: Can't find \\use_package.")
624 packageline = "\\usepackage{%s}" % pkg
625 if (del_complete_lines(document.preamble,
626 ['% Added by lyx2lyx', packageline]) or
627 del_complete_lines(document.preamble, [packageline])):
628 # package was loaded in the preamble, convert this to header setting
629 document.header.insert(i + 1, "\\use_package " + pkg + " 2") # on
630 # If oldauto is true we have two options:
631 # We can either set the package to auto - this is correct for files in
632 # format 425 to 463, and may create a conflict for older files which use
633 # any command in commands with a different definition.
634 # Or we can look whether any command in commands is used, and set it to
635 # auto if not and to off if yes. This will not create a conflict, but will
636 # create uncompilable documents for files in format 425 to 463, which use
637 # any command in commands.
638 # We choose the first option since its error is less likely.
640 document.header.insert(i + 1, "\\use_package " + pkg + " 1") # auto
644 j = find_token(document.body, '\\begin_inset Formula', j)
647 k = find_end_of_inset(document.body, j)
649 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(j))
652 code = "\n".join(document.body[j:k])
654 if code.find("\\%s" % c) != -1:
655 # at least one of the commands was found - need to switch package off
656 document.header.insert(i + 1, "\\use_package " + pkg + " 0") # off
659 # no command was found - set to auto (bug 9069)
660 document.header.insert(i + 1, "\\use_package " + pkg + " 1") # auto
663 def revert_use_package(document, pkg, commands, oldauto):
664 # oldauto defines how the version we are reverting to behaves:
665 # if it is true, the old version uses the package automatically.
666 # if it is false, the old version never uses the package.
667 regexp = re.compile(r'(\\use_package\s+%s)' % pkg)
668 i = find_re(document.header, regexp, 0)
669 value = "1" # default is auto
671 value = get_value(document.header, "\\use_package" , i).split()[1]
672 del document.header[i]
673 if value == "2": # on
674 add_to_preamble(document, ["\\usepackage{" + pkg + "}"])
675 elif value == "1" and not oldauto: # auto
678 i = find_token(document.body, '\\begin_inset Formula', i)
681 j = find_end_of_inset(document.body, i)
683 document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
686 code = "\n".join(document.body[i:j])
688 if code.find("\\%s" % c) != -1:
689 add_to_preamble(document, ["\\usepackage{" + pkg + "}"])
694 mathtools_commands = ["mathclap", "mathllap", "mathrlap", \
695 "lgathered", "rgathered", "vcentcolon", "dblcolon", \
696 "coloneqq", "Coloneqq", "coloneq", "Coloneq", "eqqcolon", \
697 "Eqqcolon", "eqcolon", "Eqcolon", "colonapprox", \
698 "Colonapprox", "colonsim", "Colonsim"]
699 def convert_use_mathtools(document):
700 "insert use_package mathtools"
701 convert_use_package(document, "mathtools", mathtools_commands, False)
704 def revert_use_mathtools(document):
705 "remove use_package mathtools"
706 revert_use_package(document, "mathtools", mathtools_commands, False)
709 # commands provided by stmaryrd.sty but LyX uses other packages:
710 # boxdot lightning, bigtriangledown, bigtriangleup
711 stmaryrd_commands = ["shortleftarrow", "shortrightarrow", "shortuparrow", \
712 "shortdownarrow", "Yup", "Ydown", "Yleft", "Yright", \
713 "varcurlyvee", "varcurlywedge", "minuso", "baro", \
714 "sslash", "bbslash", "moo", "varotimes", "varoast", \
715 "varobar", "varodot", "varoslash", "varobslash", \
716 "varocircle", "varoplus", "varominus", "boxast", \
717 "boxbar", "boxslash", "boxbslash", "boxcircle", \
718 "boxbox", "boxempty", "merge", "vartimes", \
719 "fatsemi", "sswarrow", "ssearrow", "curlywedgeuparrow", \
720 "curlywedgedownarrow", "fatslash", "fatbslash", "lbag", \
721 "rbag", "varbigcirc", "leftrightarroweq", \
722 "curlyveedownarrow", "curlyveeuparrow", "nnwarrow", \
723 "nnearrow", "leftslice", "rightslice", "varolessthan", \
724 "varogreaterthan", "varovee", "varowedge", "talloblong", \
725 "interleave", "obar", "obslash", "olessthan", \
726 "ogreaterthan", "ovee", "owedge", "oblong", "inplus", \
727 "niplus", "nplus", "subsetplus", "supsetplus", \
728 "subsetpluseq", "supsetpluseq", "Lbag", "Rbag", \
729 "llbracket", "rrbracket", "llparenthesis", \
730 "rrparenthesis", "binampersand", "bindnasrepma", \
731 "trianglelefteqslant", "trianglerighteqslant", \
732 "ntrianglelefteqslant", "ntrianglerighteqslant", \
733 "llfloor", "rrfloor", "llceil", "rrceil", "arrownot", \
734 "Arrownot", "Mapstochar", "mapsfromchar", "Mapsfromchar", \
735 "leftrightarrowtriangle", "leftarrowtriangle", \
736 "rightarrowtriangle", \
737 "bigcurlyvee", "bigcurlywedge", "bigsqcap", "bigbox", \
738 "bigparallel", "biginterleave", "bignplus", \
739 "varcopyright", "longarrownot", "Longarrownot", \
740 "Mapsto", "mapsfrom", "Mapsfrom" "Longmapsto", \
741 "longmapsfrom", "Longmapsfrom"]
742 def convert_use_stmaryrd(document):
743 "insert use_package stmaryrd"
744 convert_use_package(document, "stmaryrd", stmaryrd_commands, False)
747 def revert_use_stmaryrd(document):
748 "remove use_package stmaryrd"
749 revert_use_package(document, "stmaryrd", stmaryrd_commands, False)
752 stackrel_commands = ["stackrel"]
753 def convert_use_stackrel(document):
754 "insert use_package stackrel"
755 convert_use_package(document, "stackrel", stackrel_commands, False)
758 def revert_use_stackrel(document):
759 "remove use_package stackrel"
760 revert_use_package(document, "stackrel", stackrel_commands, False)
763 def convert_cite_engine_type(document):
764 "Determine the \\cite_engine_type from the citation engine."
765 i = find_token(document.header, "\\cite_engine", 0)
768 engine = get_value(document.header, "\\cite_engine", i)
770 engine, type = engine.split("_")
772 type = {"basic": "numerical", "jurabib": "authoryear"}[engine]
773 document.header[i] = "\\cite_engine " + engine
774 document.header.insert(i + 1, "\\cite_engine_type " + type)
777 def revert_cite_engine_type(document):
778 "Natbib had the type appended with an underscore."
779 engine_type = "numerical"
780 i = find_token(document.header, "\\cite_engine_type" , 0)
782 document.warning("No \\cite_engine_type line. Assuming numerical.")
784 engine_type = get_value(document.header, "\\cite_engine_type", i)
785 del document.header[i]
787 # We are looking for the natbib citation engine
788 i = find_token(document.header, "\\cite_engine natbib", 0)
791 document.header[i] = "\\cite_engine natbib_" + engine_type
794 def convert_cite_engine_type_default(document):
795 "Convert \\cite_engine_type to default for the basic citation engine."
796 i = find_token(document.header, "\\cite_engine basic", 0)
799 i = find_token(document.header, "\\cite_engine_type" , 0)
802 document.header[i] = "\\cite_engine_type default"
805 def revert_cite_engine_type_default(document):
806 """Revert \\cite_engine_type default.
808 Revert to numerical for the basic cite engine, otherwise to authoryear."""
809 engine_type = "authoryear"
810 i = find_token(document.header, "\\cite_engine_type default" , 0)
813 j = find_token(document.header, "\\cite_engine basic", 0)
815 engine_type = "numerical"
816 document.header[i] = "\\cite_engine_type " + engine_type
819 cancel_commands = ["cancel", "bcancel", "xcancel", "cancelto"]
820 # this is the same, as revert_use_cancel() except for the default
821 def revert_cancel(document):
822 "add cancel to the preamble if necessary"
823 revert_use_package(document, "cancel", cancel_commands, False)
826 def revert_verbatim(document, starred = False):
827 " Revert verbatim environments completely to TeX-code. "
831 layout_name = "Verbatim"
832 latex_name = "verbatim"
834 layout_name = "Verbatim*"
835 latex_name = "verbatim*"
837 subst_end = ['\\end_layout', '', '\\begin_layout Plain Layout',
839 '\\begin_layout Plain Layout', '', '',
841 'end{%s}' % (latex_name),
842 '\\end_layout', '', '\\end_inset',
843 '', '', '\\end_layout']
844 subst_begin = ['\\begin_layout Standard', '\\noindent',
845 '\\begin_inset ERT', 'status open', '',
846 '\\begin_layout Plain Layout', '', '', '\\backslash',
847 'begin{%s}' % (latex_name),
848 '\\end_layout', '', '\\begin_layout Plain Layout', '']
851 i = find_token(document.body, "\\begin_layout %s" % (layout_name), i)
854 j = find_end_of_layout(document.body, i)
856 document.warning("Malformed LyX document: Can't find end of %s layout" \
860 # delete all line breaks insets (there are no other insets)
863 n = find_token(document.body, "\\begin_inset Newline newline", l, j)
865 n = find_token(document.body, "\\begin_inset Newline linebreak", l, j)
868 m = find_end_of_inset(document.body, n)
869 del(document.body[m:m+1])
870 document.body[n:n+1] = ['\\end_layout', '', '\\begin_layout Plain Layout']
872 # we deleted a line, so the end of the inset moved forward.
873 # FIXME But we also added some lines, didn't we? I think this
876 # consecutive verbatim environments need to be connected
877 k = find_token(document.body, "\\begin_layout %s" % (layout_name), j)
878 if k == j + 2 and consecutive == False:
880 document.body[j:j+1] = ['\\end_layout', '', '\\begin_layout Plain Layout']
881 document.body[i:i+1] = subst_begin
883 if k == j + 2 and consecutive == True:
884 document.body[j:j+1] = ['\\end_layout', '', '\\begin_layout Plain Layout']
885 del(document.body[i:i+1])
887 if k != j + 2 and consecutive == True:
888 document.body[j:j+1] = subst_end
889 # the next paragraph must not be indented
890 # FIXME This seems to be causing problems, because of the
891 # hardcoded use of 19. We should figure out exactly where
892 # this needs to go by searching for the right tag.
893 document.body[j+19:j+19] = ['\\noindent']
894 del(document.body[i:i+1])
898 document.body[j:j+1] = subst_end
899 # the next paragraph must not be indented
900 # FIXME This seems to be causing problems, because of the
901 # hardcoded use of 19. We should figure out exactly where
902 # this needs to go by searching for the right tag.
903 document.body[j+19:j+19] = ['\\noindent']
904 document.body[i:i+1] = subst_begin
907 def revert_tipa(document):
908 " Revert native TIPA insets to mathed or ERT. "
911 i = find_token(document.body, "\\begin_inset IPA", i)
914 j = find_end_of_inset(document.body, i)
916 document.warning("Malformed LyX document: Can't find end of IPA inset")
920 n = find_token(document.body, "\\begin_layout", i, j)
922 document.warning("Malformed LyX document: IPA inset has no embedded layout")
925 m = find_end_of_layout(document.body, n)
927 document.warning("Malformed LyX document: Can't find end of embedded layout")
930 content = document.body[n+1:m]
931 p = find_token(document.body, "\\begin_layout", m, j)
932 if p != -1 or len(content) > 1:
934 content = document.body[i+1:j]
936 # IPA insets with multiple pars need to be wrapped by \begin{IPA}...\end{IPA}
937 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}")
938 add_to_preamble(document, ["\\usepackage{tipa,tipx}"])
940 # single-par IPA insets can be reverted to mathed
941 document.body[i:j+1] = ["\\begin_inset Formula $\\text{\\textipa{" + content[0] + "}}$", "\\end_inset"]
945 def revert_cell_rotation(document):
946 "Revert cell rotations to TeX-code"
948 load_rotating = False
952 # first, let's find out if we need to do anything
953 i = find_token(document.body, '<cell ', i)
956 j = document.body[i].find('rotate="')
958 k = document.body[i].find('"', j + 8)
959 value = document.body[i][j + 8 : k]
961 rgx = re.compile(r' rotate="[^"]+?"')
962 # remove rotate option
963 document.body[i] = rgx.sub('', document.body[i])
965 rgx = re.compile(r' rotate="[^"]+?"')
966 document.body[i] = rgx.sub(' rotate="true"', document.body[i])
968 rgx = re.compile(r' rotate="[^"]+?"')
970 # remove rotate option
971 document.body[i] = rgx.sub('', document.body[i])
973 document.body[i + 5 : i + 5] = \
974 put_cmd_in_ert("\\end{turn}")
975 document.body[i + 4 : i + 4] = \
976 put_cmd_in_ert("\\begin{turn}{" + value + "}")
982 add_to_preamble(document, ["\\@ifundefined{turnbox}{\\usepackage{rotating}}{}"])
985 def convert_cell_rotation(document):
986 'Convert cell rotation statements from "true" to "90"'
990 # first, let's find out if we need to do anything
991 i = find_token(document.body, '<cell ', i)
994 j = document.body[i].find('rotate="true"')
996 rgx = re.compile(r'rotate="[^"]+?"')
997 # convert "true" to "90"
998 document.body[i] = rgx.sub('rotate="90"', document.body[i])
1003 def revert_table_rotation(document):
1004 "Revert table rotations to TeX-code"
1006 load_rotating = False
1010 # first, let's find out if we need to do anything
1011 i = find_token(document.body, '<features ', i)
1014 j = document.body[i].find('rotate="')
1016 end_table = find_token(document.body, '</lyxtabular>', j)
1017 k = document.body[i].find('"', j + 8)
1018 value = document.body[i][j + 8 : k]
1020 rgx = re.compile(r' rotate="[^"]+?"')
1021 # remove rotate option
1022 document.body[i] = rgx.sub('', document.body[i])
1024 rgx = re.compile(r'rotate="[^"]+?"')
1025 document.body[i] = rgx.sub('rotate="true"', document.body[i])
1027 rgx = re.compile(r' rotate="[^"]+?"')
1028 load_rotating = True
1029 # remove rotate option
1030 document.body[i] = rgx.sub('', document.body[i])
1032 document.body[end_table + 3 : end_table + 3] = \
1033 put_cmd_in_ert("\\end{turn}")
1034 document.body[i - 2 : i - 2] = \
1035 put_cmd_in_ert("\\begin{turn}{" + value + "}")
1041 add_to_preamble(document, ["\\@ifundefined{turnbox}{\\usepackage{rotating}}{}"])
1044 def convert_table_rotation(document):
1045 'Convert table rotation statements from "true" to "90"'
1049 # first, let's find out if we need to do anything
1050 i = find_token(document.body, '<features ', i)
1053 j = document.body[i].find('rotate="true"')
1055 rgx = re.compile(r'rotate="[^"]+?"')
1056 # convert "true" to "90"
1057 document.body[i] = rgx.sub('rotate="90"', document.body[i])
1062 def convert_listoflistings(document):
1063 r'Convert ERT \lstlistoflistings to TOC lstlistoflistings inset'
1064 # We can support roundtrip because the command is so simple
1067 i = find_token(document.body, "\\begin_inset ERT", i)
1070 j = find_end_of_inset(document.body, i)
1072 document.warning("Malformed LyX document: Can't find end of ERT inset")
1075 ert = get_ert(document.body, i)
1076 if ert == "\\lstlistoflistings{}":
1077 document.body[i:j] = ["\\begin_inset CommandInset toc", "LatexCommand lstlistoflistings", ""]
1083 def revert_listoflistings(document):
1084 'Convert TOC lstlistoflistings inset to ERT lstlistoflistings'
1087 i = find_token(document.body, "\\begin_inset CommandInset toc", i)
1090 if document.body[i+1] == "LatexCommand lstlistoflistings":
1091 j = find_end_of_inset(document.body, i)
1093 document.warning("Malformed LyX document: Can't find end of TOC inset")
1096 subst = put_cmd_in_ert("\\lstlistoflistings{}")
1097 document.body[i:j+1] = subst
1098 add_to_preamble(document, ["\\usepackage{listings}"])
1102 def convert_use_amssymb(document):
1103 "insert use_package amssymb"
1104 regexp = re.compile(r'(\\use_package\s+amsmath)')
1105 i = find_re(document.header, regexp, 0)
1107 document.warning("Malformed LyX document: Can't find \\use_package amsmath.")
1109 value = get_value(document.header, "\\use_package" , i).split()[1]
1112 useamsmath = int(value)
1114 document.warning("Invalid \\use_package amsmath: " + value + ". Assuming auto.")
1116 j = find_token(document.preamble, "\\usepackage{amssymb}", 0)
1118 document.header.insert(i + 1, "\\use_package amssymb %d" % useamsmath)
1120 document.header.insert(i + 1, "\\use_package amssymb 2")
1121 del document.preamble[j]
1124 def revert_use_amssymb(document):
1125 "remove use_package amssymb"
1126 regexp1 = re.compile(r'(\\use_package\s+amsmath)')
1127 regexp2 = re.compile(r'(\\use_package\s+amssymb)')
1128 i = find_re(document.header, regexp1, 0)
1129 j = find_re(document.header, regexp2, 0)
1130 value1 = "1" # default is auto
1131 value2 = "1" # default is auto
1133 value1 = get_value(document.header, "\\use_package" , i).split()[1]
1135 value2 = get_value(document.header, "\\use_package" , j).split()[1]
1136 del document.header[j]
1137 if value1 != value2 and value2 == "2": # on
1138 add_to_preamble(document, ["\\usepackage{amssymb}"])
1141 def convert_use_cancel(document):
1142 "insert use_package cancel"
1143 convert_use_package(document, "cancel", cancel_commands, True)
1146 def revert_use_cancel(document):
1147 "remove use_package cancel"
1148 revert_use_package(document, "cancel", cancel_commands, True)
1151 def revert_ancientgreek(document):
1152 "Set the document language for ancientgreek to greek"
1154 if document.language == "ancientgreek":
1155 document.language = "greek"
1156 i = find_token(document.header, "\\language", 0)
1158 document.header[i] = "\\language greek"
1161 j = find_token(document.body, "\\lang ancientgreek", j)
1165 document.body[j] = document.body[j].replace("\\lang ancientgreek", "\\lang greek")
1169 def revert_languages(document):
1170 "Set the document language for new supported languages to English"
1173 polyglossia_languages = ["coptic", "divehi", "hindi", "lao", "marathi",
1174 "occitan", "sanskrit", "syriac", "tamil",
1177 babel_languages = ["kurmanji"]
1178 for lang in polyglossia_languages:
1179 revert_language(document, lang, "", lang)
1180 for lang in babel_languages:
1181 revert_language(document, lang, lang, "")
1184 def convert_armenian(document):
1185 "Use polyglossia and thus non-TeX fonts for Armenian"
1187 if document.language == "armenian":
1188 i = find_token(document.header, "\\use_non_tex_fonts", 0)
1190 document.header[i] = "\\use_non_tex_fonts true"
1193 def revert_armenian(document):
1194 "Use ArmTeX and thus TeX fonts for Armenian"
1196 if document.language == "armenian":
1197 i = find_token(document.header, "\\use_non_tex_fonts", 0)
1199 document.header[i] = "\\use_non_tex_fonts false"
1202 def revert_libertine(document):
1203 " Revert native libertine font definition to LaTeX "
1205 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1206 i = find_token(document.header, "\\font_roman libertine", 0)
1209 j = find_token(document.header, "\\font_osf true", 0)
1212 preamble = "\\usepackage"
1214 document.header[j] = "\\font_osf false"
1217 preamble += "[lining]"
1218 preamble += "{libertine-type1}"
1219 add_to_preamble(document, [preamble])
1220 document.header[i] = "\\font_roman default"
1223 def revert_txtt(document):
1224 " Revert native txtt font definition to LaTeX "
1226 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1227 i = find_token(document.header, "\\font_typewriter txtt", 0)
1229 preamble = "\\renewcommand{\\ttdefault}{txtt}"
1230 add_to_preamble(document, [preamble])
1231 document.header[i] = "\\font_typewriter default"
1234 def revert_mathdesign(document):
1235 " Revert native mathdesign font definition to LaTeX "
1237 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1243 i = find_token(document.header, "\\font_roman", 0)
1246 val = get_value(document.header, "\\font_roman", i)
1247 if val in list(mathdesign_dict.keys()):
1248 preamble = "\\usepackage[%s" % mathdesign_dict[val]
1250 j = find_token(document.header, "\\font_osf true", 0)
1253 document.header[j] = "\\font_osf false"
1254 l = find_token(document.header, "\\font_sc true", 0)
1257 document.header[l] = "\\font_sc false"
1259 preamble += ",expert"
1260 preamble += "]{mathdesign}"
1261 add_to_preamble(document, [preamble])
1262 document.header[i] = "\\font_roman default"
1265 def revert_texgyre(document):
1266 " Revert native TeXGyre font definition to LaTeX "
1268 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1269 texgyre_fonts = ["tgadventor", "tgbonum", "tgchorus", "tgcursor", \
1270 "tgheros", "tgpagella", "tgschola", "tgtermes"]
1271 i = find_token(document.header, "\\font_roman", 0)
1273 val = get_value(document.header, "\\font_roman", i)
1274 if val in texgyre_fonts:
1275 preamble = "\\usepackage{%s}" % val
1276 add_to_preamble(document, [preamble])
1277 document.header[i] = "\\font_roman default"
1278 i = find_token(document.header, "\\font_sans", 0)
1280 val = get_value(document.header, "\\font_sans", i)
1281 if val in texgyre_fonts:
1282 preamble = "\\usepackage{%s}" % val
1283 add_to_preamble(document, [preamble])
1284 document.header[i] = "\\font_sans default"
1285 i = find_token(document.header, "\\font_typewriter", 0)
1287 val = get_value(document.header, "\\font_typewriter", i)
1288 if val in texgyre_fonts:
1289 preamble = "\\usepackage{%s}" % val
1290 add_to_preamble(document, [preamble])
1291 document.header[i] = "\\font_typewriter default"
1294 def revert_ipadeco(document):
1295 " Revert IPA decorations to ERT "
1298 i = find_token(document.body, "\\begin_inset IPADeco", i)
1301 end = find_end_of_inset(document.body, i)
1303 document.warning("Can't find end of inset at line " + str(i))
1306 line = document.body[i]
1307 rx = re.compile(r'\\begin_inset IPADeco (.*)$')
1309 decotype = m.group(1)
1310 if decotype != "toptiebar" and decotype != "bottomtiebar":
1311 document.warning("Invalid IPADeco type: " + decotype)
1314 blay = find_token(document.body, "\\begin_layout Plain Layout", i, end)
1316 document.warning("Can't find layout for inset at line " + str(i))
1319 bend = find_end_of_layout(document.body, blay)
1321 document.warning("Malformed LyX document: Could not find end of IPADeco inset's layout.")
1324 substi = ["\\begin_inset ERT", "status collapsed", "",
1325 "\\begin_layout Plain Layout", "", "", "\\backslash",
1326 decotype + "{", "\\end_layout", "", "\\end_inset"]
1327 substj = ["\\size default", "", "\\begin_inset ERT", "status collapsed", "",
1328 "\\begin_layout Plain Layout", "", "}", "\\end_layout", "", "\\end_inset"]
1329 # do the later one first so as not to mess up the numbering
1330 document.body[bend:end + 1] = substj
1331 document.body[i:blay + 1] = substi
1332 i = end + len(substi) + len(substj) - (end - bend) - (blay - i) - 2
1333 add_to_preamble(document, "\\usepackage{tipa}")
1336 def revert_ipachar(document):
1337 ' Revert \\IPAChar to ERT '
1340 while i < len(document.body):
1341 m = re.match(r'(.*)\\IPAChar \\(\w+\{\w+\})(.*)', document.body[i])
1345 ipachar = m.group(2)
1348 '\\begin_inset ERT',
1349 'status collapsed', '',
1350 '\\begin_layout Standard',
1351 '', '', '\\backslash',
1356 document.body[i: i+1] = subst
1361 add_to_preamble(document, "\\usepackage{tone}")
1364 def revert_minionpro(document):
1365 " Revert native MinionPro font definition to LaTeX "
1367 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1368 i = find_token(document.header, "\\font_roman minionpro", 0)
1371 j = find_token(document.header, "\\font_osf true", 0)
1374 preamble = "\\usepackage"
1376 document.header[j] = "\\font_osf false"
1379 preamble += "{MinionPro}"
1380 add_to_preamble(document, [preamble])
1381 document.header[i] = "\\font_roman default"
1384 def revert_mathfonts(document):
1385 " Revert native math font definitions to LaTeX "
1387 i = find_token(document.header, "\\font_math", 0)
1390 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1391 val = get_value(document.header, "\\font_math", i)
1392 if val == "eulervm":
1393 add_to_preamble(document, "\\usepackage{eulervm}")
1394 elif val == "default":
1396 "lmodern": "\\renewcommand{\\rmdefault}{lmr}",
1397 "minionpro": "\\usepackage[onlytext,lf]{MinionPro}",
1398 "minionpro-osf": "\\usepackage[onlytext]{MinionPro}",
1399 "palatino": "\\renewcommand{\\rmdefault}{ppl}",
1400 "palatino-osf": "\\renewcommand{\\rmdefault}{pplj}",
1401 "times": "\\renewcommand{\\rmdefault}{ptm}",
1402 "utopia": "\\renewcommand{\\rmdefault}{futs}",
1403 "utopia-osf": "\\renewcommand{\\rmdefault}{futj}",
1405 j = find_token(document.header, "\\font_roman", 0)
1407 rm = get_value(document.header, "\\font_roman", j)
1408 k = find_token(document.header, "\\font_osf true", 0)
1411 if rm in list(mathfont_dict.keys()):
1412 add_to_preamble(document, mathfont_dict[rm])
1413 document.header[j] = "\\font_roman default"
1415 document.header[k] = "\\font_osf false"
1416 del document.header[i]
1419 def revert_mdnomath(document):
1420 " Revert mathdesign and fourier without math "
1422 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1424 "md-charter": "mdbch",
1425 "md-utopia": "mdput",
1426 "md-garamond": "mdugm"
1428 i = find_token(document.header, "\\font_roman", 0)
1431 val = get_value(document.header, "\\font_roman", i)
1432 if val in list(mathdesign_dict.keys()):
1433 j = find_token(document.header, "\\font_math", 0)
1435 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1436 mval = get_value(document.header, "\\font_math", j)
1437 if mval == "default":
1438 document.header[i] = "\\font_roman default"
1439 add_to_preamble(document, "\\renewcommand{\\rmdefault}{%s}" % mathdesign_dict[val])
1441 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1444 def convert_mathfonts(document):
1445 document.header.insert(-1, "\\font_math auto")
1448 def convert_mdnomath(document):
1449 " Change mathdesign font name "
1451 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1453 "mdbch": "md-charter",
1454 "mdput": "md-utopia",
1455 "mdugm": "md-garamond"
1457 i = find_token(document.header, "\\font_roman", 0)
1460 val = get_value(document.header, "\\font_roman", i)
1461 if val in list(mathdesign_dict.keys()):
1462 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
1465 def revert_newtxmath(document):
1466 " Revert native newtxmath definitions to LaTeX "
1468 i = find_token(document.header, "\\font_math", 0)
1471 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1472 val = get_value(document.header, "\\font_math", i)
1474 "libertine-ntxm": "\\usepackage[libertine]{newtxmath}",
1475 "minion-ntxm": "\\usepackage[minion]{newtxmath}",
1476 "newtxmath": "\\usepackage{newtxmath}",
1478 if val in list(mathfont_dict.keys()):
1479 add_to_preamble(document, mathfont_dict[val])
1480 document.header[i] = "\\font_math auto"
1483 def revert_biolinum(document):
1484 " Revert native biolinum font definition to LaTeX "
1486 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1487 i = find_token(document.header, "\\font_sans biolinum", 0)
1490 j = find_token(document.header, "\\font_osf true", 0)
1493 preamble = "\\usepackage"
1496 preamble += "{biolinum-type1}"
1497 add_to_preamble(document, [preamble])
1498 document.header[i] = "\\font_sans default"
1501 def revert_uop(document):
1502 " Revert native URW Classico (Optima) font definition to LaTeX "
1504 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
1505 i = find_token(document.header, "\\font_sans uop", 0)
1507 preamble = "\\renewcommand{\\sfdefault}{uop}"
1508 add_to_preamble(document, [preamble])
1509 document.header[i] = "\\font_sans default"
1512 def convert_latexargs(document):
1513 " Convert InsetArgument to new syntax "
1515 if find_token(document.body, "\\begin_inset Argument", 0) == -1:
1519 # A list of layouts (document classes) with only optional or no arguments.
1520 # These can be safely converted to the new syntax
1521 # (I took the liberty to add some of my personal layouts/modules here; JSP)
1522 safe_layouts = ["aa", "aapaper", "aastex", "achemso", "acmsiggraph", "AEA",
1523 "agu-dtd", "agums", "agutex", "amsart", "amsbook", "apa",
1524 "arab-article", "armenian-article", "article-beamer", "article",
1525 "beamer", "book", "broadway", "chess", "cl2emult", "ctex-article",
1526 "ctex-book", "ctex-report", "dinbrief", "docbook-book", "docbook-chapter",
1527 "docbook", "docbook-section", "doublecol-new", "dtk", "ectaart", "egs",
1528 "elsarticle", "elsart", "entcs", "europecv", "extarticle", "extbook",
1529 "extletter", "extreport", "foils", "frletter", "g-brief2", "g-brief",
1530 "heb-article", "heb-letter", "hollywood", "IEEEtran", "ijmpc", "ijmpd",
1531 "iopart", "isprs", "jarticle", "jasatex", "jbook", "jgrga", "jreport",
1532 "jsarticle", "jsbeamer", "jsbook", "jss", "kluwer", "latex8", "letter", "lettre",
1533 "literate-article", "literate-book", "literate-report", "llncs", "ltugboat",
1534 "memoir", "moderncv", "mwart", "mwbk", "mwrep", "paper", "powerdot",
1535 "recipebook", "report", "revtex4", "revtex", "scrartcl", "scrarticle-beamer",
1536 "scrbook", "scrlettr", "scrlttr2", "scrreprt", "seminar", "siamltex",
1537 "sigplanconf", "simplecv", "singlecol", "singlecol-new", "slides", "spie",
1538 "svglobal3", "svglobal", "svjog", "svmono", "svmult", "svprobth", "tarticle",
1539 "tbook", "treport", "tufte-book", "tufte-handout"]
1540 # A list of "safe" modules, same as above
1541 safe_modules = ["biblatex", "beameraddons", "beamer-resenumerate", "beamersession", "braille",
1542 "customHeadersFooters", "endnotes", "enumitem", "eqs-within-sections", "figs-within-sections",
1543 "fix-cm", "fixltx2e", "foottoend", "hanging", "jscharstyles", "knitr", "lilypond",
1544 "linguistics", "linguisticx", "logicalmkup", "minimalistic", "nomindex", "noweb",
1545 "pdfcomment", "sweave", "tabs-within-sections", "theorems-ams-bytype",
1546 "theorems-ams-extended-bytype", "theorems-ams-extended", "theorems-ams", "theorems-bytype",
1547 "theorems-chap-bytype", "theorems-chap", "theorems-named", "theorems-sec-bytype",
1548 "theorems-sec", "theorems-starred", "theorems-std", "todonotes"]
1549 # Modules we need to take care of
1550 caveat_modules = ["initials"] # TODO: , "graphicboxes", "bicaption"]
1551 # information about the relevant styles in caveat_modules (number of opt and req args)
1552 # use this if we get more caveat_modules. For now, use hard coding (see below).
1553 # initials = [{'Layout' : 'Initial', 'opt' : 1, 'req' : 1}]
1554 # graphicboxes = { ... }
1556 # Is this a known safe layout?
1557 safe_layout = document.textclass in safe_layouts
1559 document.warning("Lyx2lyx knows nothing about textclass '%s'. "
1560 "Please check if short title insets have been converted correctly."
1561 % document.textclass)
1562 # Do we use unsafe or unknown modules
1563 mods = document.get_module_list()
1564 unknown_modules = False
1565 used_caveat_modules = list()
1567 if mod in safe_modules:
1569 if mod in caveat_modules:
1570 used_caveat_modules.append(mod)
1572 unknown_modules = True
1573 document.warning("Lyx2lyx knows nothing about module '%s'. "
1574 "Please check if short title insets have been converted correctly."
1579 i = find_token(document.body, "\\begin_inset Argument", i)
1583 if not safe_layout or unknown_modules:
1584 # We cannot do more here since we have no access to this layout.
1585 # InsetArgument itself will do the real work
1586 # (see InsetArgument::updateBuffer())
1587 document.body[i] = "\\begin_inset Argument 999"
1591 # Find containing paragraph layout
1592 parent = get_containing_layout(document.body, i)
1594 document.warning("Malformed LyX document: Can't find parent paragraph layout")
1601 if len(used_caveat_modules) > 0:
1602 # We know for now that this must be the initials module with the Initial layout
1603 # If we get more such modules, we need some automating.
1604 if parent[0] == "Initial":
1605 # Layout has 1 opt and 1 req arg.
1606 # Count the actual arguments
1608 for p in range(parbeg, parend):
1609 if document.body[p] == "\\begin_inset Argument":
1614 # Collect all arguments in this paragraph
1616 for p in range(parbeg, parend):
1617 if document.body[p] == "\\begin_inset Argument":
1619 if allowed_opts != -1:
1620 # We have less arguments than opt + required.
1621 # required must take precedence.
1622 if argnr > allowed_opts and argnr < first_req:
1624 document.body[p] = "\\begin_inset Argument %d" % argnr
1628 def revert_latexargs(document):
1629 " Revert InsetArgument to old syntax "
1632 rx = re.compile(r'^\\begin_inset Argument (\d+)$')
1635 # Search for Argument insets
1636 i = find_token(document.body, "\\begin_inset Argument", i)
1639 m = rx.match(document.body[i])
1641 # No ID: inset already reverted
1644 # Find containing paragraph layout
1645 parent = get_containing_layout(document.body, i)
1647 document.warning("Malformed LyX document: Can't find parent paragraph layout")
1652 # Do not set realparbeg to parent[3], since this does not work if we
1653 # have another inset (e.g. label or index) before the first argument
1654 # inset (this is the case in the user guide of LyX 2.0.8)
1656 # Collect all arguments in this paragraph
1658 for p in range(parbeg, parend):
1659 m = rx.match(document.body[p])
1662 # This is the first argument inset
1664 val = int(m.group(1))
1665 j = find_end_of_inset(document.body, p)
1666 # Revert to old syntax
1667 document.body[p] = "\\begin_inset Argument"
1669 document.warning("Malformed LyX document: Can't find end of Argument inset")
1672 args[val] = document.body[p : j + 1]
1674 realparend = realparend - len(document.body[p : j + 1])
1675 # Remove arg inset at this position
1676 del document.body[p : j + 1]
1680 # No argument inset found
1681 realparbeg = parent[3]
1682 # Now sort the arg insets
1684 for f in sorted(args):
1687 # Insert the sorted arg insets at paragraph begin
1688 document.body[realparbeg : realparbeg] = subst
1690 i = realparbeg + 1 + len(subst)
1693 def revert_IEEEtran(document):
1695 Reverts InsetArgument of
1698 Biography without photo
1701 if document.textclass != "IEEEtran":
1704 layouts = {"Page headings": False,
1705 "Biography without photo": True}
1707 for layout in list(layouts.keys()):
1710 i = find_token(document.body, '\\begin_layout ' + layout, i)
1713 revert_Argument_to_TeX_brace(document, i, 0, 1, 1, layouts[layout], False)
1718 i = find_token(document.body, '\\begin_inset Flex Paragraph Start', i)
1721 revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1726 i = find_token_exact(document.body, "\\begin_layout Biography", i)
1730 if document.body[i] == "\\begin_layout Biography without photo":
1734 # start with the second argument, therefore 2
1735 revert_Argument_to_TeX_brace(document, i, 0, 2, 2, True, False)
1739 def revert_IEEEtran_2(document):
1741 Reverts Flex Paragraph Start to TeX-code
1743 if document.textclass == "IEEEtran":
1746 begin = find_token(document.body, "\\begin_inset Flex Paragraph Start", begin)
1749 end1 = find_end_of_inset(document.body, begin)
1750 document.body[end1 - 2 : end1 + 1] = put_cmd_in_ert("}")
1751 document.body[begin : begin + 4] = put_cmd_in_ert("\\IEEEPARstart{")
1755 def convert_IEEEtran(document):
1760 Biography without photo
1763 if document.textclass != "IEEEtran":
1766 layouts = {"Page headings": False,
1767 "Biography without photo": True}
1769 for layout in list(layouts.keys()):
1772 i = find_token(document.body, '\\begin_layout ' + layout, i)
1775 convert_TeX_brace_to_Argument(document, i, 1, 1, False, layouts[layout], False)
1780 i = find_token_exact(document.body, "\\begin_layout Biography", i)
1784 if document.body[i] == "\\begin_layout Biography without photo":
1788 # the argument we want to convert is the second one
1789 convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, False)
1793 def revert_AASTeX(document):
1794 " Reverts InsetArgument of Altaffilation to TeX-code "
1795 if document.textclass == "aastex":
1798 i = find_token(document.body, "\\begin_layout Altaffilation", i)
1801 revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1805 def convert_AASTeX(document):
1806 " Converts ERT of Altaffilation to InsetArgument "
1807 if document.textclass == "aastex":
1810 i = find_token(document.body, "\\begin_layout Altaffilation", i)
1813 convert_TeX_brace_to_Argument(document, i, 1, 1, False, False, False)
1817 def revert_AGUTeX(document):
1818 " Reverts InsetArgument of Author affiliation to TeX-code "
1819 if document.textclass == "agutex":
1822 i = find_token(document.body, "\\begin_layout Author affiliation", i)
1825 revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1829 def convert_AGUTeX(document):
1830 " Converts ERT of Author affiliation to InsetArgument "
1831 if document.textclass == "agutex":
1834 i = find_token(document.body, "\\begin_layout Author affiliation", i)
1837 convert_TeX_brace_to_Argument(document, i, 1, 1, False, False, False)
1841 def revert_IJMP(document):
1842 " Reverts InsetArgument of MarkBoth to TeX-code "
1843 if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1846 i = find_token(document.body, "\\begin_layout MarkBoth", i)
1849 revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1853 def convert_IJMP(document):
1854 " Converts ERT of MarkBoth to InsetArgument "
1855 if document.textclass == "ijmpc" or document.textclass == "ijmpd":
1858 i = find_token(document.body, "\\begin_layout MarkBoth", i)
1861 convert_TeX_brace_to_Argument(document, i, 1, 1, False, False, False)
1865 def revert_SIGPLAN(document):
1866 " Reverts InsetArguments of SIGPLAN to TeX-code "
1867 if document.textclass == "sigplanconf":
1872 i = find_token(document.body, "\\begin_layout Conference", i)
1874 revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
1877 j = find_token(document.body, "\\begin_layout Author", j)
1879 revert_Argument_to_TeX_brace(document, j, 0, 1, 2, False, False)
1881 if i == -1 and j == -1:
1885 def convert_SIGPLAN(document):
1886 " Converts ERT of SIGPLAN to InsetArgument "
1887 if document.textclass == "sigplanconf":
1892 i = find_token(document.body, "\\begin_layout Conference", i)
1894 convert_TeX_brace_to_Argument(document, i, 1, 1, False, False, False)
1897 j = find_token(document.body, "\\begin_layout Author", j)
1899 convert_TeX_brace_to_Argument(document, j, 1, 2, False, False, False)
1901 if i == -1 and j == -1:
1905 def revert_SIGGRAPH(document):
1906 " Reverts InsetArgument of Flex CRcat to TeX-code "
1907 if document.textclass == "acmsiggraph":
1910 i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1913 revert_Argument_to_TeX_brace(document, i, 0, 1, 3, False, False)
1917 def convert_SIGGRAPH(document):
1918 " Converts ERT of Flex CRcat to InsetArgument "
1919 if document.textclass == "acmsiggraph":
1922 i = find_token(document.body, "\\begin_inset Flex CRcat", i)
1925 convert_TeX_brace_to_Argument(document, i, 1, 3, True, False, False)
1929 def revert_EuropeCV(document):
1930 " Reverts InsetArguments of europeCV to TeX-code "
1931 if document.textclass == "europecv":
1938 i = find_token(document.body, "\\begin_layout Item", i)
1940 revert_Argument_to_TeX_brace(document, i, 0, 2, 2, False, False)
1943 j = find_token(document.body, "\\begin_layout BulletedItem", j)
1945 revert_Argument_to_TeX_brace(document, j, 0, 2, 2, False, False)
1948 k = find_token(document.body, "\\begin_layout Language", k)
1950 revert_Argument_to_TeX_brace(document, k, 0, 2, 6, False, False)
1953 m = find_token(document.body, "\\begin_layout LastLanguage", m)
1955 revert_Argument_to_TeX_brace(document, m, 0, 2, 6, False, False)
1957 if i == -1 and j == -1 and k == -1 and m == -1:
1961 def convert_EuropeCV(document):
1962 " Converts ERT of europeCV to InsetArgument "
1963 if document.textclass == "europecv":
1970 i = find_token(document.body, "\\begin_layout Item", i)
1972 convert_TeX_brace_to_Argument(document, i, 2, 2, False, False, False)
1975 j = find_token(document.body, "\\begin_layout BulletedItem", j)
1977 convert_TeX_brace_to_Argument(document, j, 2, 2, False, False, False)
1980 k = find_token(document.body, "\\begin_layout Language", k)
1982 convert_TeX_brace_to_Argument(document, k, 2, 6, False, False, False)
1985 m = find_token(document.body, "\\begin_layout LastLanguage", m)
1987 convert_TeX_brace_to_Argument(document, m, 2, 6, False, False, False)
1989 if i == -1 and j == -1 and k == -1 and m == -1:
1993 def revert_ModernCV(document):
1994 " Reverts InsetArguments of modernCV to TeX-code "
1995 if document.textclass == "moderncv":
2003 j = find_token(document.body, "\\begin_layout Entry", j)
2005 revert_Argument_to_TeX_brace(document, j, 0, 1, 5, False, False)
2008 k = find_token(document.body, "\\begin_layout Item", k)
2010 revert_Argument_to_TeX_brace(document, k, 0, 1, 1, False, False)
2013 m = find_token(document.body, "\\begin_layout ItemWithComment", m)
2015 revert_Argument_to_TeX_brace(document, m, 0, 1, 2, False, False)
2016 document.body[m] = document.body[m].replace("\\begin_layout ItemWithComment", "\\begin_layout Language")
2019 o = find_token(document.body, "\\begin_layout DoubleItem", o)
2021 revert_Argument_to_TeX_brace(document, o, 0, 1, 3, False, False)
2022 document.body[o] = document.body[o].replace("\\begin_layout DoubleItem", "\\begin_layout Computer")
2025 p = find_token(document.body, "\\begin_layout Social", p)
2027 revert_Argument_to_TeX_brace(document, p, 0, 1, 1, False, True)
2029 if j == -1 and k == -1 and m == -1 and o == -1 and p == -1:
2033 def revert_ModernCV_2(document):
2034 " Reverts the Flex:Column inset of modernCV to TeX-code "
2035 if document.textclass == "moderncv":
2039 flex = find_token(document.body, "\\begin_inset Flex Column", flex)
2042 flexEnd = find_end_of_inset(document.body, flex)
2043 wasOpt = revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, False, True)
2044 revert_Argument_to_TeX_brace(document, flex, 0, 2, 2, False, False)
2045 flexEnd = find_end_of_inset(document.body, flex)
2047 document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\cvcolumn")
2049 document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\cvcolumn{")
2050 document.body[flexEnd + 4 : flexEnd + 7] = put_cmd_in_ert("}")
2054 def revert_ModernCV_3(document):
2055 " Reverts the Column style of modernCV to TeX-code "
2056 if document.textclass == "moderncv":
2057 # revert the layouts
2058 revert_ModernCV(document)
2060 # get the position of the end of the last column inset
2061 LastFlexEnd = revert_ModernCV_2(document)
2063 p = find_token(document.body, "\\begin_layout Columns", p)
2066 pEnd = find_end_of_layout(document.body, p)
2067 document.body[p] = document.body[p].replace("\\begin_layout Columns", "\\begin_layout Standard")
2068 if LastFlexEnd != -1:
2069 document.body[p + 1 : p + 1] = put_cmd_in_ert("\\begin{cvcolumns}")
2070 document.body[LastFlexEnd + 24 : LastFlexEnd + 24] = put_cmd_in_ert("\\end{cvcolumns}")
2074 def revert_ModernCV_4(document):
2075 " Reverts the style Social to TeX-code "
2076 if document.textclass == "moderncv":
2077 # revert the layouts
2078 revert_ModernCV(document)
2081 p = find_token(document.body, "\\begin_layout Social", p)
2084 pEnd = find_end_of_layout(document.body, p)
2085 document.body[p] = document.body[p].replace("\\begin_layout Social", "\\begin_layout Standard")
2086 document.body[p + 1 : p + 1] = put_cmd_in_ert("\\social")
2087 hasOpt = find_token(document.body, "[", p + 9)
2089 document.body[p + 30 : p + 30] = put_cmd_in_ert("{")
2090 document.body[p + 41 : p + 41] = put_cmd_in_ert("}")
2092 document.body[p + 11 : p + 11] = put_cmd_in_ert("{")
2093 document.body[p + 21 : p + 21] = put_cmd_in_ert("}")
2097 def convert_ModernCV(document):
2098 " Converts ERT of modernCV to InsetArgument "
2099 if document.textclass == "moderncv":
2107 i = find_token(document.body, "\\begin_layout DoubleItem", i)
2109 convert_TeX_brace_to_Argument(document, i, 1, 1, False, False, False)
2110 document.body[o] = document.body[o].replace("\\begin_layout DoubleItem", "\\begin_layout DoubleListItem")
2113 j = find_token(document.body, "\\begin_layout Entry", j)
2115 convert_TeX_brace_to_Argument(document, j, 1, 5, False, False, False)
2118 k = find_token(document.body, "\\begin_layout Item", k)
2120 convert_TeX_brace_to_Argument(document, k, 1, 1, False, False, False)
2123 m = find_token(document.body, "\\begin_layout Language", m)
2125 convert_TeX_brace_to_Argument(document, m, 1, 2, False, False, False)
2127 if i == -1 and j == -1 and k == -1 and m == -1:
2131 def revert_Initials(document):
2132 " Reverts InsetArgument of Initial to TeX-code "
2135 i = find_token(document.body, "\\begin_layout Initial", i)
2138 # first arg (optional) and second arg (first mandatory) are supported in LyX 2.0.x
2139 revert_Argument_to_TeX_brace(document, i, 0, 3, 3, False, False)
2143 def convert_Initials(document):
2144 " Converts ERT of Initial to InsetArgument "
2147 i = find_token(document.body, "\\begin_layout Initial", i)
2150 convert_TeX_brace_to_Argument(document, i, 3, 3, False, False, False)
2154 def revert_literate(document):
2155 " Revert Literate document to old format "
2156 if del_token(document.header, "noweb", 0):
2157 document.textclass = "literate-" + document.textclass
2160 i = find_token(document.body, "\\begin_layout Chunk", i)
2163 document.body[i] = "\\begin_layout Scrap"
2167 def convert_literate(document):
2168 " Convert Literate document to new format"
2169 i = find_token(document.header, "\\textclass", 0)
2170 if (i != -1) and "literate-" in document.header[i]:
2171 document.textclass = document.header[i].replace("\\textclass literate-", "")
2172 j = find_token(document.header, "\\begin_modules", 0)
2174 document.header.insert(j + 1, "noweb")
2176 document.header.insert(i + 1, "\\end_modules")
2177 document.header.insert(i + 1, "noweb")
2178 document.header.insert(i + 1, "\\begin_modules")
2181 i = find_token(document.body, "\\begin_layout Scrap", i)
2184 document.body[i] = "\\begin_layout Chunk"
2188 def revert_itemargs(document):
2189 " Reverts \\item arguments to TeX-code "
2192 i = find_token(document.body, "\\begin_inset Argument item:", i)
2195 j = find_end_of_inset(document.body, i)
2196 # Find containing paragraph layout
2197 parent = get_containing_layout(document.body, i)
2199 document.warning("Malformed LyX document: Can't find parent paragraph layout")
2203 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2204 endPlain = find_end_of_layout(document.body, beginPlain)
2205 content = document.body[beginPlain + 1 : endPlain]
2206 del document.body[i:j+1]
2207 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2208 document.body[parbeg : parbeg] = subst
2212 def revert_garamondx_newtxmath(document):
2213 " Revert native garamond newtxmath definition to LaTeX "
2215 i = find_token(document.header, "\\font_math", 0)
2218 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
2219 val = get_value(document.header, "\\font_math", i)
2220 if val == "garamondx-ntxm":
2221 add_to_preamble(document, "\\usepackage[garamondx]{newtxmath}")
2222 document.header[i] = "\\font_math auto"
2225 def revert_garamondx(document):
2226 " Revert native garamond font definition to LaTeX "
2228 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
2229 i = find_token(document.header, "\\font_roman garamondx", 0)
2232 j = find_token(document.header, "\\font_osf true", 0)
2235 preamble = "\\usepackage"
2237 preamble += "[osfI]"
2238 preamble += "{garamondx}"
2239 add_to_preamble(document, [preamble])
2240 document.header[i] = "\\font_roman default"
2243 def convert_beamerargs(document):
2244 " Converts beamer arguments to new layout "
2246 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2247 if document.textclass not in beamer_classes:
2250 shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2251 list_layouts = ["Itemize", "Enumerate", "Description"]
2252 rx = re.compile(r'^\\begin_inset Argument (\d+)$')
2256 i = find_token(document.body, "\\begin_inset Argument", i)
2259 # Find containing paragraph layout
2260 parent = get_containing_layout(document.body, i)
2262 document.warning("Malformed LyX document: Can't find parent paragraph layout")
2267 layoutname = parent[0]
2268 for p in range(parbeg, parend):
2269 if layoutname in shifted_layouts:
2270 m = rx.match(document.body[p])
2272 argnr = int(m.group(1))
2274 document.body[p] = "\\begin_inset Argument %d" % argnr
2275 if layoutname == "AgainFrame":
2276 m = rx.match(document.body[p])
2278 document.body[p] = "\\begin_inset Argument 3"
2279 if document.body[p + 4] == "\\begin_inset ERT":
2280 if document.body[p + 9].startswith("<"):
2281 # This is an overlay specification
2283 document.body[p + 9] = document.body[p + 9][1:]
2284 if document.body[p + 9].endswith(">"):
2286 document.body[p + 9] = document.body[p + 9][:-1]
2288 document.body[p] = "\\begin_inset Argument 2"
2289 if layoutname in list_layouts:
2290 m = rx.match(document.body[p])
2292 if m.group(1) == "1":
2293 if document.body[p + 4] == "\\begin_inset ERT":
2294 if document.body[p + 9].startswith("<"):
2295 # This is an overlay specification
2297 document.body[p + 9] = document.body[p + 9][1:]
2298 if document.body[p + 9].endswith(">"):
2300 document.body[p + 9] = document.body[p + 9][:-1]
2301 elif document.body[p + 4].startswith("<"):
2302 # This is an overlay specification (without ERT)
2304 document.body[p + 4] = document.body[p + 4][1:]
2305 if document.body[p + 4].endswith(">"):
2307 document.body[p + 4] = document.body[p + 4][:-1]
2308 elif layoutname != "Itemize":
2310 document.body[p] = "\\begin_inset Argument 2"
2315 # Helper function for the frame conversion routines
2317 # FIXME: This method currently requires the arguments to be either
2318 # * In one (whole) ERT each: <ERT>[<arg1>]</ERT><ERT><arg2></ERT><ERT>[arg3]</ERT>
2319 # * Altogether in one whole ERT: <ERT>[<arg1>]<arg2>[arg3]</ERT>
2320 # If individual arguments mix ERT and non-ERT or are splitted
2321 # over several ERTs, the parsing fails.
2322 def convert_beamerframeargs(document, i, parbeg):
2325 if document.body[parbeg] != "\\begin_inset ERT":
2327 ertend = find_end_of_inset(document.body, parbeg)
2329 document.warning("Malformed LyX document: missing ERT \\end_inset")
2331 ertcont = parbeg + 5
2332 if document.body[ertcont].startswith("[<"):
2333 # This is a default overlay specification
2335 document.body[ertcont] = document.body[ertcont][2:]
2336 if document.body[ertcont].endswith(">]"):
2338 document.body[ertcont] = document.body[ertcont][:-2]
2339 elif document.body[ertcont].endswith("]"):
2341 tok = document.body[ertcont].find('>][')
2343 subst = [document.body[ertcont][:tok],
2344 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2345 'status collapsed', '', '\\begin_layout Plain Layout',
2346 document.body[ertcont][tok + 3:-1]]
2347 document.body[ertcont : ertcont + 1] = subst
2349 # Convert to ArgInset
2350 document.body[parbeg] = "\\begin_inset Argument 2"
2351 elif document.body[ertcont].startswith("<"):
2352 # This is an overlay specification
2354 document.body[ertcont] = document.body[ertcont][1:]
2355 if document.body[ertcont].endswith(">"):
2357 document.body[ertcont] = document.body[ertcont][:-1]
2358 # Convert to ArgInset
2359 document.body[parbeg] = "\\begin_inset Argument 1"
2360 elif document.body[ertcont].endswith(">]"):
2362 tok = document.body[ertcont].find('>[<')
2364 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2365 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2366 'status collapsed', '', '\\begin_layout Plain Layout',
2367 document.body[ertcont][tok + 3:-2]]
2368 # Convert to ArgInset
2369 document.body[parbeg] = "\\begin_inset Argument 1"
2371 elif document.body[ertcont].endswith("]"):
2373 tok = document.body[ertcont].find('>[<')
2376 tokk = document.body[ertcont].find('>][')
2378 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok],
2379 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2380 'status collapsed', '', '\\begin_layout Plain Layout',
2381 document.body[ertcont][tok + 3:tokk],
2382 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2383 'status collapsed', '', '\\begin_layout Plain Layout',
2384 document.body[ertcont][tokk + 3:-1]]
2387 tokk = document.body[ertcont].find('>[')
2389 document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tokk],
2390 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 3',
2391 'status collapsed', '', '\\begin_layout Plain Layout',
2392 document.body[ertcont][tokk + 2:-1]]
2394 # Convert to ArgInset
2395 document.body[parbeg] = "\\begin_inset Argument 1"
2396 elif document.body[ertcont].startswith("["):
2397 # This is an ERT option
2399 document.body[ertcont] = document.body[ertcont][1:]
2400 if document.body[ertcont].endswith("]"):
2402 document.body[ertcont] = document.body[ertcont][:-1]
2403 # Convert to ArgInset
2404 document.body[parbeg] = "\\begin_inset Argument 3"
2410 def convert_againframe_args(document):
2411 " Converts beamer AgainFrame to new layout "
2413 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2414 if document.textclass not in beamer_classes:
2419 i = find_token(document.body, "\\begin_layout AgainFrame", i)
2422 parent = get_containing_layout(document.body, i)
2424 document.warning("Wrong parent layout!")
2428 # Convert ERT arguments
2429 # FIXME: See restrictions in convert_beamerframeargs method
2430 ertend = convert_beamerframeargs(document, i, parbeg)
2436 def convert_corollary_args(document):
2437 " Converts beamer corrolary-style ERT arguments native InsetArgs "
2439 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2440 if document.textclass not in beamer_classes:
2443 corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2444 for lay in corollary_layouts:
2447 i = find_token_exact(document.body, "\\begin_layout " + lay, i)
2450 parent = get_containing_layout(document.body, i)
2452 document.warning("Wrong parent layout!")
2456 if document.body[parbeg] == "\\begin_inset ERT":
2457 ertcontfirstline = parbeg + 5
2458 # Find the last ERT in this paragraph (which might also be the first)
2459 lastertbeg = find_token_backwards(document.body, "\\begin_inset ERT", j)
2460 if lastertbeg == -1:
2461 document.warning("Last ERT not found!")
2463 lastertend = find_end_of_inset(document.body, lastertbeg)
2464 if lastertend == -1:
2465 document.warning("End of last ERT not found!")
2467 ertcontlastline = lastertend - 3
2468 if document.body[ertcontfirstline].startswith("<"):
2469 # This is an overlay specification
2471 document.body[ertcontfirstline] = document.body[ertcontfirstline][1:]
2472 if document.body[ertcontlastline].endswith(">"):
2474 document.body[ertcontlastline] = document.body[ertcontlastline][:-1]
2475 if ertcontfirstline < ertcontlastline:
2476 # Multiline ERT. Might contain TeX code. Embrace in ERT.
2477 document.body[ertcontlastline : ertcontlastline + 1] = [
2478 document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
2479 document.body[ertcontfirstline : ertcontfirstline + 1] = [
2480 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
2481 'status collapsed', '', '\\begin_layout Plain Layout',
2482 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
2483 document.body[ertcontfirstline]]
2485 # Convert to ArgInset
2486 document.body[parbeg] = "\\begin_inset Argument 1"
2487 elif document.body[ertcontlastline].endswith("]"):
2489 tok = document.body[ertcontfirstline].find('>[')
2491 if ertcontfirstline < ertcontlastline:
2492 # Multiline ERT. Might contain TeX code. Embrace in ERT.
2493 document.body[ertcontlastline : ertcontlastline + 1] = [
2494 document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
2495 document.body[ertcontfirstline : ertcontfirstline + 1] = [document.body[ertcontfirstline][:tok],
2496 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2497 'status collapsed', '', '\\begin_layout Plain Layout',
2498 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
2499 document.body[ertcontfirstline][tok + 2:-1]]
2501 document.body[ertcontfirstline : ertcontfirstline + 1] = [document.body[ertcontfirstline][:tok],
2502 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
2503 'status collapsed', '', '\\begin_layout Plain Layout',
2504 document.body[ertcontfirstline][tok + 2:-1]]
2505 # Convert to ArgInset
2506 document.body[parbeg] = "\\begin_inset Argument 1"
2509 elif document.body[ertcontlastline].startswith("["):
2510 if document.body[ertcontlastline].endswith("]"):
2511 # This is an ERT option
2513 document.body[ertcontlastline] = document.body[ertcontlastline][1:]
2515 document.body[ertcontlastline] = document.body[ertcontlastline][:-1]
2516 # Convert to ArgInset
2517 document.body[parbeg] = "\\begin_inset Argument 2"
2519 convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, True)
2526 def convert_quote_args(document):
2527 " Converts beamer quote style ERT args to native InsetArgs "
2529 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2530 if document.textclass not in beamer_classes:
2533 quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2534 for lay in quote_layouts:
2537 i = find_token(document.body, "\\begin_layout " + lay, i)
2540 parent = get_containing_layout(document.body, i)
2542 document.warning("Wrong parent layout!")
2546 if document.body[parbeg] == "\\begin_inset ERT":
2547 if document.body[i + 6].startswith("<"):
2548 # This is an overlay specification
2550 document.body[i + 6] = document.body[i + 6][1:]
2551 if document.body[i + 6].endswith(">"):
2553 document.body[i + 6] = document.body[i + 6][:-1]
2554 # Convert to ArgInset
2555 document.body[i + 1] = "\\begin_inset Argument 1"
2559 def cleanup_beamerargs(document):
2560 " Clean up empty ERTs (conversion artefacts) "
2562 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2563 if document.textclass not in beamer_classes:
2568 i = find_token(document.body, "\\begin_inset Argument", i)
2571 j = find_end_of_inset(document.body, i)
2573 document.warning("Malformed LyX document: Can't find end of Argument inset")
2577 ertbeg = find_token(document.body, "\\begin_inset ERT", i, j)
2580 ertend = find_end_of_inset(document.body, ertbeg)
2582 document.warning("Malformed LyX document: Can't find end of ERT inset")
2584 stripped = [line for line in document.body[ertbeg : ertend + 1] if line.strip()]
2585 if len(stripped) == 5:
2586 # This is an empty ERT
2587 offset = len(document.body[ertbeg : ertend + 1])
2588 del document.body[ertbeg : ertend + 1]
2595 def revert_beamerargs(document):
2596 " Reverts beamer arguments to old layout "
2598 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2599 if document.textclass not in beamer_classes:
2603 list_layouts = ["Itemize", "Enumerate", "Description"]
2604 headings = ["Part", "Section", "Section*", "Subsection", "Subsection*",
2605 "Subsubsection", "Subsubsection*", "FrameSubtitle", "NoteItem"]
2606 quote_layouts = ["Uncover", "Only", "Quotation", "Quote", "Verse"]
2607 corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2608 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2611 i = find_token(document.body, "\\begin_inset Argument", i)
2614 # Find containing paragraph layout
2615 parent = get_containing_layout(document.body, i)
2617 document.warning("Malformed LyX document: Can't find parent paragraph layout")
2622 realparbeg = parent[3]
2623 layoutname = parent[0]
2625 for p in range(parbeg, parend):
2629 if layoutname in headings:
2630 m = rx.match(document.body[p])
2634 # Find containing paragraph layout
2635 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2636 endPlain = find_end_of_layout(document.body, beginPlain)
2637 endInset = find_end_of_inset(document.body, p)
2638 argcontent = document.body[beginPlain + 1 : endPlain]
2640 realparend = realparend - len(document.body[p : endInset + 1])
2642 del document.body[p : endInset + 1]
2643 if layoutname == "FrameSubtitle":
2644 pre = put_cmd_in_ert("\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2645 elif layoutname == "NoteItem":
2646 pre = put_cmd_in_ert("\\note<") + argcontent + put_cmd_in_ert(">[item]")
2647 elif layoutname.endswith('*'):
2648 pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower()[:-1] + "<") + argcontent + put_cmd_in_ert(">*")
2650 pre = put_cmd_in_ert("\\lyxframeend\\" + layoutname.lower() + "<") + argcontent + put_cmd_in_ert(">")
2651 secarg = find_token(document.body, "\\begin_inset Argument 2", parbeg, parend)
2653 # Find containing paragraph layout
2654 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", secarg)
2655 endPlain = find_end_of_layout(document.body, beginPlain)
2656 endInset = find_end_of_inset(document.body, secarg)
2657 argcontent = document.body[beginPlain + 1 : endPlain]
2659 realparend = realparend - len(document.body[secarg : endInset + 1])
2660 del document.body[secarg : endInset + 1]
2661 pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2662 pre += put_cmd_in_ert("{")
2663 document.body[parbeg] = "\\begin_layout Standard"
2664 document.body[realparbeg : realparbeg] = pre
2665 pe = find_end_of_layout(document.body, parbeg)
2666 post = put_cmd_in_ert("}")
2667 document.body[pe : pe] = post
2668 realparend += len(pre) + len(post)
2669 if layoutname == "AgainFrame":
2670 m = rx.match(document.body[p])
2674 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2675 endPlain = find_end_of_layout(document.body, beginPlain)
2676 endInset = find_end_of_inset(document.body, p)
2677 content = document.body[beginPlain + 1 : endPlain]
2679 realparend = realparend - len(document.body[p : endInset + 1])
2681 del document.body[p : endInset + 1]
2682 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2683 document.body[realparbeg : realparbeg] = subst
2684 if layoutname == "Overprint":
2685 m = rx.match(document.body[p])
2689 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2690 endPlain = find_end_of_layout(document.body, beginPlain)
2691 endInset = find_end_of_inset(document.body, p)
2692 content = document.body[beginPlain + 1 : endPlain]
2694 realparend = realparend - len(document.body[p : endInset + 1])
2696 del document.body[p : endInset + 1]
2697 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2698 document.body[realparbeg : realparbeg] = subst
2699 if layoutname == "OverlayArea":
2700 m = rx.match(document.body[p])
2704 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2705 endPlain = find_end_of_layout(document.body, beginPlain)
2706 endInset = find_end_of_inset(document.body, p)
2707 content = document.body[beginPlain + 1 : endPlain]
2709 realparend = realparend - len(document.body[p : endInset + 1])
2711 del document.body[p : endInset + 1]
2712 subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2713 document.body[realparbeg : realparbeg] = subst
2714 if layoutname in list_layouts:
2715 m = rx.match(document.body[p])
2719 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2720 endPlain = find_end_of_layout(document.body, beginPlain)
2721 endInset = find_end_of_inset(document.body, p)
2722 content = document.body[beginPlain + 1 : endPlain]
2723 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2724 realparend = realparend + len(subst) - len(content)
2725 document.body[beginPlain + 1 : endPlain] = subst
2726 elif argnr == "item:1":
2727 j = find_end_of_inset(document.body, i)
2728 # Find containing paragraph layout
2729 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2730 endPlain = find_end_of_layout(document.body, beginPlain)
2731 content = document.body[beginPlain + 1 : endPlain]
2732 del document.body[i:j+1]
2733 if layoutname == "Description":
2734 # Description only has one (overlay) item arg
2735 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2736 # This must be put after the first space (begin of decription body
2737 # in LyX's arkward description list syntax)
2738 # Try to find that place ...
2739 rxx = re.compile(r'^([^\\ ]+ )(.*)$')
2740 for q in range(parbeg, parend):
2741 m = rxx.match(document.body[q])
2743 # We found it. Now insert the ERT argument just there:
2744 document.body[q : q] = [m.group(1), ''] + subst + ['', m.group(2)]
2747 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2748 document.body[realparbeg : realparbeg] = subst
2749 elif argnr == "item:2":
2750 j = find_end_of_inset(document.body, i)
2751 # Find containing paragraph layout
2752 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2753 endPlain = find_end_of_layout(document.body, beginPlain)
2754 content = document.body[beginPlain + 1 : endPlain]
2755 del document.body[i:j+1]
2756 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2757 document.body[realparbeg : realparbeg] = subst
2758 if layoutname in quote_layouts:
2759 m = rx.match(document.body[p])
2763 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2764 endPlain = find_end_of_layout(document.body, beginPlain)
2765 endInset = find_end_of_inset(document.body, p)
2766 content = document.body[beginPlain + 1 : endPlain]
2768 realparend = realparend - len(document.body[p : endInset + 1])
2770 del document.body[p : endInset + 1]
2771 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2772 document.body[realparbeg : realparbeg] = subst
2773 if layoutname in corollary_layouts:
2774 m = rx.match(document.body[p])
2778 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2779 endPlain = find_end_of_layout(document.body, beginPlain)
2780 endInset = find_end_of_inset(document.body, p)
2781 content = document.body[beginPlain + 1 : endPlain]
2783 realparend = realparend - len(document.body[p : endInset + 1])
2785 del document.body[p : endInset + 1]
2786 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
2787 document.body[realparbeg : realparbeg] = subst
2792 def revert_beamerargs2(document):
2793 " Reverts beamer arguments to old layout, step 2 "
2795 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2796 if document.textclass not in beamer_classes:
2800 shifted_layouts = ["Part", "Section", "Subsection", "Subsubsection"]
2801 corollary_layouts = ["Corollary", "Definition", "Definitions", "Example", "Examples", "Fact", "Proof", "Theorem"]
2802 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2805 i = find_token(document.body, "\\begin_inset Argument", i)
2808 # Find containing paragraph layout
2809 parent = get_containing_layout(document.body, i)
2811 document.warning("Malformed LyX document: Can't find parent paragraph layout")
2816 realparbeg = parent[3]
2817 layoutname = parent[0]
2819 for p in range(parbeg, parend):
2823 if layoutname in shifted_layouts:
2824 m = rx.match(document.body[p])
2828 document.body[p] = "\\begin_inset Argument 1"
2829 if layoutname in corollary_layouts:
2830 m = rx.match(document.body[p])
2834 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2835 endPlain = find_end_of_layout(document.body, beginPlain)
2836 endInset = find_end_of_inset(document.body, p)
2837 content = document.body[beginPlain + 1 : endPlain]
2839 realparend = realparend - len(document.body[p : endInset + 1])
2841 del document.body[p : endInset + 1]
2842 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2843 document.body[realparbeg : realparbeg] = subst
2844 if layoutname == "OverlayArea":
2845 m = rx.match(document.body[p])
2849 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2850 endPlain = find_end_of_layout(document.body, beginPlain)
2851 endInset = find_end_of_inset(document.body, p)
2852 content = document.body[beginPlain + 1 : endPlain]
2854 realparend = realparend - len(document.body[p : endInset + 1])
2856 del document.body[p : endInset + 1]
2857 subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
2858 document.body[realparbeg : realparbeg] = subst
2859 if layoutname == "AgainFrame":
2860 m = rx.match(document.body[p])
2864 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2865 endPlain = find_end_of_layout(document.body, beginPlain)
2866 endInset = find_end_of_inset(document.body, p)
2867 content = document.body[beginPlain + 1 : endPlain]
2869 realparend = realparend - len(document.body[p : endInset + 1])
2871 del document.body[p : endInset + 1]
2872 subst = put_cmd_in_ert("[<") + content + put_cmd_in_ert(">]")
2873 document.body[realparbeg : realparbeg] = subst
2877 def revert_beamerargs3(document):
2878 " Reverts beamer arguments to old layout, step 3 "
2880 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2881 if document.textclass not in beamer_classes:
2884 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
2887 i = find_token(document.body, "\\begin_inset Argument", i)
2890 # Find containing paragraph layout
2891 parent = get_containing_layout(document.body, i)
2893 document.warning("Malformed LyX document: Can't find parent paragraph layout")
2898 realparbeg = parent[3]
2899 layoutname = parent[0]
2901 for p in range(parbeg, parend):
2905 if layoutname == "AgainFrame":
2906 m = rx.match(document.body[p])
2910 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
2911 endPlain = find_end_of_layout(document.body, beginPlain)
2912 endInset = find_end_of_inset(document.body, p)
2913 content = document.body[beginPlain + 1 : endPlain]
2915 realparend = realparend - len(document.body[p : endInset + 1])
2917 del document.body[p : endInset + 1]
2918 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
2919 document.body[realparbeg : realparbeg] = subst
2923 def revert_beamerflex(document):
2924 " Reverts beamer Flex insets "
2926 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
2927 if document.textclass not in beamer_classes:
2930 new_flexes = {"Bold" : "\\textbf", "Emphasize" : "\\emph", "Only" : "\\only",
2931 "Uncover" : "\\uncover", "Visible" : "\\visible",
2932 "Invisible" : "\\invisible", "Alternative" : "\\alt",
2933 "Beamer_Note" : "\\note"}
2934 old_flexes = {"Alert" : "\\alert", "Structure" : "\\structure"}
2935 rx = re.compile(r'^\\begin_inset Flex (.+)$')
2939 i = find_token(document.body, "\\begin_inset Flex", i)
2942 m = rx.match(document.body[i])
2944 flextype = m.group(1)
2945 z = find_end_of_inset(document.body, i)
2947 document.warning("Can't find end of Flex " + flextype + " inset.")
2950 if flextype in new_flexes:
2951 pre = put_cmd_in_ert(new_flexes[flextype])
2952 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
2954 argend = find_end_of_inset(document.body, arg)
2956 document.warning("Can't find end of Argument!")
2959 # Find containing paragraph layout
2960 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2961 endPlain = find_end_of_layout(document.body, beginPlain)
2962 argcontent = document.body[beginPlain + 1 : endPlain]
2964 z = z - len(document.body[arg : argend + 1])
2966 del document.body[arg : argend + 1]
2967 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
2968 arg = find_token(document.body, "\\begin_inset Argument 2", i, z)
2970 argend = find_end_of_inset(document.body, arg)
2972 document.warning("Can't find end of Argument!")
2975 # Find containing paragraph layout
2976 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
2977 endPlain = find_end_of_layout(document.body, beginPlain)
2978 argcontent = document.body[beginPlain + 1 : endPlain]
2980 z = z - len(document.body[arg : argend + 1])
2982 del document.body[arg : argend + 1]
2983 if flextype == "Alternative":
2984 pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
2986 pre += put_cmd_in_ert("[") + argcontent + put_cmd_in_ert("]")
2987 pre += put_cmd_in_ert("{")
2988 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2989 endPlain = find_end_of_layout(document.body, beginPlain)
2991 z = z - len(document.body[i : beginPlain + 1])
2993 document.body[i : beginPlain + 1] = pre
2994 post = put_cmd_in_ert("}")
2995 document.body[z - 2 : z + 1] = post
2996 elif flextype in old_flexes:
2997 pre = put_cmd_in_ert(old_flexes[flextype])
2998 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
3002 argend = find_end_of_inset(document.body, arg)
3004 document.warning("Can't find end of Argument!")
3007 # Find containing paragraph layout
3008 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3009 endPlain = find_end_of_layout(document.body, beginPlain)
3010 argcontent = document.body[beginPlain + 1 : endPlain]
3012 z = z - len(document.body[arg : argend + 1])
3014 del document.body[arg : argend + 1]
3015 pre += put_cmd_in_ert("<") + argcontent + put_cmd_in_ert(">")
3016 pre += put_cmd_in_ert("{")
3017 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
3018 endPlain = find_end_of_layout(document.body, beginPlain)
3020 z = z - len(document.body[i : beginPlain + 1])
3022 document.body[i : beginPlain + 1] = pre
3023 post = put_cmd_in_ert("}")
3024 document.body[z - 2 : z + 1] = post
3029 def revert_beamerblocks(document):
3030 " Reverts beamer block arguments to ERT "
3032 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3033 if document.textclass not in beamer_classes:
3036 blocks = ["Block", "ExampleBlock", "AlertBlock"]
3038 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3041 i = find_token(document.body, "\\begin_inset Argument", i)
3044 # Find containing paragraph layout
3045 parent = get_containing_layout(document.body, i)
3047 document.warning("Malformed LyX document: Can't find parent paragraph layout")
3052 realparbeg = parent[3]
3053 layoutname = parent[0]
3055 for p in range(parbeg, parend):
3059 if layoutname in blocks:
3060 m = rx.match(document.body[p])
3064 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3065 endPlain = find_end_of_layout(document.body, beginPlain)
3066 endInset = find_end_of_inset(document.body, p)
3067 content = document.body[beginPlain + 1 : endPlain]
3069 realparend = realparend - len(document.body[p : endInset + 1])
3071 del document.body[p : endInset + 1]
3072 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3073 document.body[realparbeg : realparbeg] = subst
3075 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3076 endPlain = find_end_of_layout(document.body, beginPlain)
3077 endInset = find_end_of_inset(document.body, p)
3078 content = document.body[beginPlain + 1 : endPlain]
3080 realparend = realparend - len(document.body[p : endInset + 1])
3082 del document.body[p : endInset + 1]
3083 subst = put_cmd_in_ert("{") + content + put_cmd_in_ert("}")
3084 document.body[realparbeg : realparbeg] = subst
3089 def convert_beamerblocks(document):
3090 " Converts beamer block ERT args to native InsetArgs "
3092 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3093 if document.textclass not in beamer_classes:
3096 blocks = ["Block", "ExampleBlock", "AlertBlock"]
3100 i = find_token_exact(document.body, "\\begin_layout " + lay, i)
3103 parent = get_containing_layout(document.body, i)
3104 if parent == False or parent[1] != i:
3105 document.warning("Wrong parent layout!")
3112 # If the paragraph starts with a language switch, adjust parbeg
3113 if len(document.body[parbeg]) == 0 and parbeg < parend \
3114 and document.body[parbeg + 1].startswith("\\lang"):
3116 if document.body[parbeg] == "\\begin_inset ERT":
3117 ertcontfirstline = parbeg + 5
3121 # Find the last ERT in this paragraph used for arguments
3122 # (which might also be the first)
3123 lastertbeg = find_token_backwards(document.body, "\\begin_inset ERT", j)
3124 if lastertbeg == -1:
3125 document.warning("Last ERT not found!")
3127 lastertend = find_end_of_inset(document.body, lastertbeg)
3128 if lastertend == -1:
3129 document.warning("End of last ERT not found!")
3131 # Is this ERT really used for an argument?
3132 # Note: This will fail when non-argument ERTs actually use brackets
3134 regexp = re.compile(r'.*[>\]\}]', re.IGNORECASE)
3135 cbracket = find_re(document.body, regexp, lastertbeg, lastertend)
3138 if lastertbeg == parbeg:
3141 if lastertbeg == -1 or lastertend == -1:
3143 ertcontlastline = lastertend - 3
3145 if document.body[ertcontfirstline].lstrip().startswith("<"):
3146 # This is an overlay specification
3148 document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3149 if document.body[ertcontlastline].rstrip().endswith(">"):
3151 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3152 # Convert to ArgInset
3153 document.body[parbeg] = "\\begin_inset Argument 1"
3154 elif document.body[ertcontlastline].rstrip().endswith("}"):
3156 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3158 ertcontdivline = ertcontfirstline
3159 tok = document.body[ertcontdivline].find('>{')
3161 regexp = re.compile(r'.*>\{', re.IGNORECASE)
3162 ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3163 tok = document.body[ertcontdivline].find('>{')
3165 if ertcontfirstline < ertcontlastline:
3166 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3167 document.body[ertcontlastline : ertcontlastline + 1] = [
3168 document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3169 if ertcontdivline == ertcontfirstline:
3170 document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3171 '\\end_layout', '', '\\end_inset', '',
3172 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3173 'status collapsed', '', '\\begin_layout Plain Layout',
3174 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3175 document.body[ertcontdivline][tok + 2:]]
3177 document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3178 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3179 'status collapsed', '', '\\begin_layout Plain Layout',
3180 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3181 document.body[ertcontdivline][tok + 2:]]
3183 document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3184 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3185 'status collapsed', '', '\\begin_layout Plain Layout',
3186 document.body[ertcontdivline][tok + 2:]]
3188 # check if have delimiters in two different ERTs
3189 tok = document.body[ertcontdivline].find('>')
3191 regexp = re.compile(r'.*>', re.IGNORECASE)
3192 ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3193 tok = document.body[ertcontdivline].find('>')
3195 tokk = document.body[ertcontdivline].find('{')
3197 regexp = re.compile(r'.*\{', re.IGNORECASE)
3198 ertcontdivlinetwo = find_re(document.body, regexp, ertcontfirstline, lastertend)
3199 tokk = document.body[ertcontdivlinetwo].find('{')
3201 if ertcontfirstline < ertcontlastline:
3202 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3203 document.body[ertcontlastline : ertcontlastline + 1] = [
3204 document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3205 document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3206 '\\end_layout', '', '\\end_inset', '', '\\end_layout', '',
3207 '\\end_inset', '', '', '\\begin_inset Argument 2',
3208 'status collapsed', '', '\\begin_layout Plain Layout',
3209 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3210 document.body[ertcontdivlinetwo][tokk + 1:]]
3212 document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3213 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2',
3214 'status collapsed', '', '\\begin_layout Plain Layout',
3215 document.body[ertcontdivlinetwo][tokk + 1:]]
3216 # Convert to ArgInset
3217 if ertcontfirstline < ertcontlastline:
3218 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3219 document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 1',
3220 'status collapsed', '', '\\begin_layout Plain Layout',
3221 '\\begin_inset ERT', '']
3223 document.body[parbeg] = "\\begin_inset Argument 1"
3224 elif document.body[ertcontfirstline].lstrip().startswith("{"):
3225 # This is the block title
3226 if document.body[ertcontlastline].rstrip().endswith("}"):
3227 # strip off the braces
3228 document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3229 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3230 if ertcontfirstline < ertcontlastline:
3231 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3232 document.body[parend : parend + 1] = [
3233 document.body[parend], '\\end_inset', '', '\\end_layout']
3234 document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 2',
3235 'status collapsed', '', '\\begin_layout Plain Layout',
3236 '\\begin_inset ERT', '']
3238 # Convert to ArgInset
3239 document.body[parbeg] = "\\begin_inset Argument 2"
3240 # the overlay argument can also follow the title, so ...
3241 elif document.body[ertcontlastline].rstrip().endswith(">"):
3243 document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:]
3245 document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1]
3247 ertcontdivline = ertcontfirstline
3248 tok = document.body[ertcontdivline].find('}<')
3250 regexp = re.compile(r'.*\}<', re.IGNORECASE)
3251 ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3252 tok = document.body[ertcontdivline].find('}<')
3254 if ertcontfirstline < ertcontlastline:
3255 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3256 document.body[ertcontlastline : ertcontlastline + 1] = [
3257 document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3258 if ertcontdivline == ertcontfirstline:
3259 document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3260 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3261 'status collapsed', '', '\\begin_layout Plain Layout',
3262 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3263 document.body[ertcontdivline][tok + 2:]]
3265 document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3266 '\\end_layout', '', '\\end_inset', '',
3267 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3268 'status collapsed', '', '\\begin_layout Plain Layout',
3269 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3270 document.body[ertcontdivline][tok + 2:]]
3272 document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok],
3273 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3274 'status collapsed', '', '\\begin_layout Plain Layout',
3275 document.body[ertcontdivline][tok + 2:]]
3277 # check if have delimiters in two different ERTs
3278 tok = document.body[ertcontdivline].find('}')
3280 regexp = re.compile(r'.*\}', re.IGNORECASE)
3281 ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend)
3282 tok = document.body[ertcontdivline].find('}')
3284 tokk = document.body[ertcontdivline].find('<')
3286 regexp = re.compile(r'.*<', re.IGNORECASE)
3287 ertcontdivlinetwo = find_re(document.body, regexp, ertcontfirstline, lastertend)
3288 tokk = document.body[ertcontdivlinetwo].find('<')
3290 if ertcontfirstline < ertcontlastline:
3291 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3292 document.body[ertcontlastline : ertcontlastline + 1] = [
3293 document.body[ertcontlastline], '\\end_layout', '', '\\end_inset']
3294 document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3295 '\\end_layout', '', '\\end_inset', '', '\\end_layout', '',
3296 '\\end_inset', '', '', '\\begin_inset Argument 1',
3297 'status collapsed', '', '\\begin_layout Plain Layout',
3298 '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout',
3299 document.body[ertcontdivlinetwo][tokk + 1:]]
3301 document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok],
3302 '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1',
3303 'status collapsed', '', '\\begin_layout Plain Layout',
3304 document.body[ertcontdivlinetwo][tokk + 1:]]
3305 # Convert to ArgInset
3306 if ertcontfirstline < ertcontlastline:
3307 # Multiline ERT. Might contain TeX code. Embrace in ERT.
3308 document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 2',
3309 'status collapsed', '', '\\begin_layout Plain Layout',
3310 '\\begin_inset ERT', '']
3312 document.body[parbeg] = "\\begin_inset Argument 2"
3313 elif count_pars_in_inset(document.body, ertcontfirstline) > 1:
3314 # Multipar ERT. Skip this.
3317 # ERT has contents after the closing bracket. We cannot convert this.
3318 # convert_TeX_brace_to_Argument cannot either.
3319 #convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, False)
3323 j = find_end_of_layout(document.body, i)
3325 document.warning("end of layout not found!")
3326 k = find_token(document.body, "\\begin_inset Argument", i, j)
3328 document.warning("InsetArgument not found!")
3330 l = find_end_of_inset(document.body, k)
3331 m = find_token(document.body, "\\begin_inset ERT", l, j)
3334 ertcontfirstline = m + 5
3339 def convert_overprint(document):
3340 " Convert old beamer overprint layouts to ERT "
3342 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3343 if document.textclass not in beamer_classes:
3348 i = find_token(document.body, "\\begin_layout Overprint", i)
3351 # Find end of sequence
3352 j = find_end_of_sequence(document.body, i)
3354 document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
3358 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
3360 if document.body[j] == "\\end_deeper":
3361 esubst = ["", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
3363 esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + ["\\end_layout"]
3364 endseq = endseq + len(esubst) - len(document.body[j : j])
3365 document.body[j : j] = esubst
3366 argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3368 argend = find_end_of_layout(document.body, argbeg)
3370 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3373 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3374 endPlain = find_end_of_layout(document.body, beginPlain)
3375 content = document.body[beginPlain + 1 : endPlain]
3377 endseq = endseq - len(document.body[argbeg : argend + 1])
3379 del document.body[argbeg : argend + 1]
3380 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3382 endseq = endseq - len(document.body[i : i])
3383 document.body[i : i] = subst + ["\\end_layout"]
3384 endseq += len(subst)
3386 for p in range(i, endseq):
3387 if document.body[p] == "\\begin_layout Overprint":
3388 document.body[p] = "\\begin_layout Standard"
3393 def revert_overprint(document):
3394 " Revert old beamer overprint layouts to ERT "
3396 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3397 if document.textclass not in beamer_classes:
3402 i = find_token(document.body, "\\begin_layout Overprint", i)
3405 # Find end of sequence
3406 j = find_end_of_sequence(document.body, i)
3408 document.warning("Malformed LyX document. Cannot find end of Overprint sequence!")
3412 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}")
3413 esubst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}")
3414 endseq = endseq + len(esubst) - len(document.body[j : j])
3415 if document.body[j] == "\\end_deeper":
3416 document.body[j : j] = [""] + esubst + ["", "\\end_layout"]
3418 document.body[j : j] = ["\\end_layout", ""] + esubst
3421 if document.body[r] == "\\begin_deeper":
3422 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3424 document.body[r] = ""
3425 document.body[s] = ""
3429 argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j)
3431 # Is this really our argument?
3432 nested = find_token(document.body, "\\begin_deeper", i, argbeg)
3434 argend = find_end_of_inset(document.body, argbeg)
3436 document.warning("Malformed LyX document. Cannot find end of Overprint argument!")
3439 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3440 endPlain = find_end_of_layout(document.body, beginPlain)
3441 content = document.body[beginPlain + 1 : endPlain]
3443 endseq = endseq - len(document.body[argbeg : argend])
3445 del document.body[argbeg : argend + 1]
3446 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3448 endseq = endseq - len(document.body[i : i])
3449 document.body[i : i] = subst + ["\\end_layout"]
3450 endseq += len(subst)
3456 if document.body[p] == "\\begin_layout Overprint":
3457 q = find_end_of_layout(document.body, p)
3459 document.warning("Malformed LyX document. Cannot find end of Overprint layout!")
3462 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\onslide")
3463 argbeg = find_token(document.body, "\\begin_inset Argument item:1", p, q)
3465 argend = find_end_of_inset(document.body, argbeg)
3467 document.warning("Malformed LyX document. Cannot find end of Overprint item argument!")
3470 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg)
3471 endPlain = find_end_of_layout(document.body, beginPlain)
3472 content = document.body[beginPlain + 1 : endPlain]
3474 endseq = endseq - len(document.body[argbeg : argend + 1])
3476 del document.body[argbeg : argend + 1]
3477 subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3478 endseq = endseq - len(document.body[p : p + 1]) + len(subst)
3479 document.body[p : p + 1] = subst
3485 def revert_frametitle(document):
3486 " Reverts beamer frametitle layout to ERT "
3488 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3489 if document.textclass not in beamer_classes:
3492 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
3495 i = find_token(document.body, "\\begin_layout FrameTitle", i)
3498 j = find_end_of_layout(document.body, i)
3500 document.warning("Malformed LyX document: Can't find end of FrameTitle layout")
3504 document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
3505 endlay += len(put_cmd_in_ert("}"))
3506 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\frametitle")
3507 for p in range(i, j):
3510 m = rx.match(document.body[p])
3514 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3515 endPlain = find_end_of_layout(document.body, beginPlain)
3516 endInset = find_end_of_inset(document.body, p)
3517 content = document.body[beginPlain + 1 : endPlain]
3519 endlay = endlay - len(document.body[p : endInset + 1])
3521 del document.body[p : endInset + 1]
3522 subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
3524 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3525 endPlain = find_end_of_layout(document.body, beginPlain)
3526 endInset = find_end_of_inset(document.body, p)
3527 content = document.body[beginPlain + 1 : endPlain]
3529 endlay = endlay - len(document.body[p : endInset + 1])
3531 del document.body[p : endInset + 1]
3532 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
3534 subst += put_cmd_in_ert("{")
3535 document.body[i : i + 1] = subst
3539 def convert_epigraph(document):
3540 " Converts memoir epigraph to new syntax "
3542 if document.textclass != "memoir":
3547 i = find_token(document.body, "\\begin_layout Epigraph", i)
3550 j = find_end_of_layout(document.body, i)
3552 document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3557 ert = find_token(document.body, "\\begin_inset ERT", i, j)
3559 endInset = find_end_of_inset(document.body, ert)
3560 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", ert)
3561 endPlain = find_end_of_layout(document.body, beginPlain)
3562 ertcont = beginPlain + 2
3563 if document.body[ertcont] == "}{":
3565 # Convert to ArgInset
3566 endlay = endlay - 2 * len(document.body[j])
3567 begsubst = ['\\begin_inset Argument post:1', 'status collapsed', '',
3568 '\\begin_layout Plain Layout']
3569 endsubst = ['\\end_layout', '', '\\end_inset', '', document.body[j]]
3570 document.body[j : j + 1] = endsubst
3571 document.body[endInset + 1 : endInset + 1] = begsubst
3573 endlay += len(begsubst) + len(endsubst)
3574 endlay = endlay - len(document.body[ert : endInset + 1])
3575 del document.body[ert : endInset + 1]
3580 def revert_epigraph(document):
3581 " Reverts memoir epigraph argument to ERT "
3583 if document.textclass != "memoir":
3588 i = find_token(document.body, "\\begin_layout Epigraph", i)
3591 j = find_end_of_layout(document.body, i)
3593 document.warning("Malformed LyX document: Can't find end of Epigraph layout")
3598 p = find_token(document.body, "\\begin_layout Argument post:1", i, j)
3600 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
3601 endPlain = find_end_of_layout(document.body, beginPlain)
3602 endInset = find_end_of_inset(document.body, p)
3603 content = document.body[beginPlain + 1 : endPlain]
3605 endlay = endlay - len(document.body[p : endInset + 1])
3607 del document.body[p : endInset + 1]
3608 subst += put_cmd_in_ert("}{") + content
3610 subst += put_cmd_in_ert("}{")
3612 document.body[j : j] = subst + document.body[j : j]
3616 def convert_captioninsets(document):
3617 " Converts caption insets to new syntax "
3621 i = find_token(document.body, "\\begin_inset Caption", i)
3624 document.body[i] = "\\begin_inset Caption Standard"
3628 def revert_captioninsets(document):
3629 " Reverts caption insets to old syntax "
3633 i = find_token(document.body, "\\begin_inset Caption Standard", i)
3636 document.body[i] = "\\begin_inset Caption"
3640 def convert_captionlayouts(document):
3641 " Convert caption layouts to caption insets. "
3644 "Captionabove": "Above",
3645 "Captionbelow": "Below",
3646 "FigCaption" : "FigCaption",
3647 "Table_Caption" : "Table",
3648 "CenteredCaption" : "Centered",
3649 "Bicaption" : "Bicaption",
3652 for captype in caption_dict.keys():
3655 i = find_token(document.body, "\\begin_layout " + captype, i)
3658 j = find_end_of_layout(document.body, i)
3660 document.warning("Malformed LyX document: Missing `\\end_layout'.")
3663 document.body[j:j] = ["\\end_layout", "", "\\end_inset", "", ""]
3664 document.body[i:i+1] = ["\\begin_layout %s" % document.default_layout,
3665 "\\begin_inset Caption %s" % caption_dict[captype], "",
3666 "\\begin_layout %s" % document.default_layout]
3670 def revert_captionlayouts(document):
3671 " Revert caption insets to caption layouts. "
3674 "Above" : "Captionabove",
3675 "Below" : "Captionbelow",
3676 "FigCaption" : "FigCaption",
3677 "Table" : "Table_Caption",
3678 "Centered" : "CenteredCaption",
3679 "Bicaption" : "Bicaption",
3683 rx = re.compile(r'^\\begin_inset Caption (\S+)$')
3685 i = find_token(document.body, "\\begin_inset Caption", i)
3689 m = rx.match(document.body[i])
3693 if val not in list(caption_dict.keys()):
3697 # We either need to delete the previous \begin_layout line, or we
3698 # need to end the previous layout if this inset is not in the first
3699 # position of the paragraph.
3700 layout_before = find_token_backwards(document.body, "\\begin_layout", i)
3701 if layout_before == -1:
3702 document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3704 layout_line = document.body[layout_before]
3705 del_layout_before = True
3706 l = layout_before + 1
3708 if document.body[l] != "":
3709 del_layout_before = False
3712 if del_layout_before:
3713 del document.body[layout_before:i]
3716 document.body[i:i] = ["\\end_layout", ""]
3719 # Find start of layout in the inset and end of inset
3720 j = find_token(document.body, "\\begin_layout", i)
3722 document.warning("Malformed LyX document: Missing `\\begin_layout'.")
3724 k = find_end_of_inset(document.body, i)
3726 document.warning("Malformed LyX document: Missing `\\end_inset'.")
3729 # We either need to delete the following \end_layout line, or we need
3730 # to restart the old layout if this inset is not at the paragraph end.
3731 layout_after = find_token(document.body, "\\end_layout", k)
3732 if layout_after == -1:
3733 document.warning("Malformed LyX document: Missing `\\end_layout'.")
3735 del_layout_after = True
3737 while l < layout_after:
3738 if document.body[l] != "":
3739 del_layout_after = False
3742 if del_layout_after:
3743 del document.body[k+1:layout_after+1]
3745 document.body[k+1:k+1] = [layout_line, ""]
3747 # delete \begin_layout and \end_inset and replace \begin_inset with
3748 # "\begin_layout XXX". This works because we can only have one
3749 # paragraph in the caption inset: The old \end_layout will be recycled.
3750 del document.body[k]
3751 if document.body[k] == "":
3752 del document.body[k]
3753 del document.body[j]
3754 if document.body[j] == "":
3755 del document.body[j]
3756 document.body[i] = "\\begin_layout %s" % caption_dict[val]
3757 if document.body[i+1] == "":
3758 del document.body[i+1]
3762 def revert_fragileframe(document):
3763 " Reverts beamer FragileFrame layout to ERT "
3765 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3766 if document.textclass not in beamer_classes:
3771 i = find_token(document.body, "\\begin_layout FragileFrame", i)
3774 # Find end of sequence
3775 j = find_end_of_sequence(document.body, i)
3777 document.warning("Malformed LyX document. Cannot find end of FragileFrame sequence!")
3781 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{frame}")
3782 esubst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\end{frame}")
3783 endseq = endseq + len(esubst) - len(document.body[j : j])
3784 if document.body[j] == "\\end_deeper":
3785 document.body[j : j] = [""] + esubst + ["", "\\end_layout"]
3787 document.body[j : j] = esubst
3788 for q in range(i, j):
3789 if document.body[q] == "\\begin_layout FragileFrame":
3790 document.body[q] = "\\begin_layout %s" % document.default_layout
3793 if document.body[r] == "\\begin_deeper":
3794 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3796 document.body[r] = ""
3797 document.body[s] = ""
3801 for p in range(1, 5):
3802 arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, j)
3805 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3806 endPlain = find_end_of_layout(document.body, beginPlain)
3807 endInset = find_end_of_inset(document.body, arg)
3808 content = document.body[beginPlain + 1 : endPlain]
3810 j = j - len(document.body[arg : endInset + 1])
3812 del document.body[arg : endInset + 1]
3813 subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
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("[fragile,") + 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("{") + content + put_cmd_in_ert("}")
3845 subst += put_cmd_in_ert("[fragile]")
3847 document.body[i : i + 1] = subst
3851 def revert_newframes(document):
3852 " Reverts beamer Frame and PlainFrame layouts to old forms "
3854 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
3855 if document.textclass not in beamer_classes:
3859 "Frame" : "BeginFrame",
3860 "PlainFrame" : "BeginPlainFrame",
3863 rx = re.compile(r'^\\begin_layout (\S+)$')
3866 i = find_token(document.body, "\\begin_layout", i)
3870 m = rx.match(document.body[i])
3874 if val not in list(frame_dict.keys()):
3877 # Find end of sequence
3878 j = find_end_of_sequence(document.body, i)
3880 document.warning("Malformed LyX document. Cannot find end of Frame sequence!")
3884 subst = ["\\begin_layout %s" % frame_dict[val]]
3885 esubst = ["", "\\begin_layout EndFrame", "", "\\end_layout"]
3886 endseq = endseq + len(esubst) - len(document.body[j : j])
3887 if document.body[j] == "\\end_deeper":
3888 document.body[j : j] = esubst
3890 document.body[j+1 : j+1] = esubst
3891 for q in range(i, j):
3892 if document.body[q] == "\\begin_layout %s" % val:
3893 document.body[q] = "\\begin_layout %s" % document.default_layout
3896 if document.body[r] == "\\begin_deeper":
3897 s = find_end_of(document.body, r, "\\begin_deeper", "\\end_deeper")
3899 document.body[r] = ""
3900 document.body[s] = ""
3904 l = find_end_of_layout(document.body, i)
3905 for p in range(1, 5):
3906 arg = find_token(document.body, "\\begin_inset Argument %d" % p, i, l)
3909 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
3910 endPlain = find_end_of_layout(document.body, beginPlain)
3911 endInset = find_end_of_inset(document.body, arg)
3912 content = document.body[beginPlain + 1 : endPlain]
3914 l = l - len(document.body[arg : endInset + 1])
3916 del document.body[arg : endInset + 1]
3917 subst += put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
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]
3949 document.body[i : i + 1] = subst
3952 # known encodings that do not change their names (same LyX and LaTeX names)
3953 known_enc_tuple = ("auto", "default", "ansinew", "applemac", "armscii8", "ascii",
3954 "cp437", "cp437de", "cp850", "cp852", "cp855", "cp858", "cp862", "cp865", "cp866",
3955 "cp1250", "cp1251", "cp1252", "cp1255", "cp1256", "cp1257", "koi8-r", "koi8-u",
3956 "pt154", "pt254", "tis620-0", "utf8", "utf8x", "utf8-plain")
3958 def convert_encodings(document):
3959 "Use the LyX names of the encodings instead of the LaTeX names."
3960 LaTeX2LyX_enc_dict = {
3961 "8859-6": "iso8859-6",
3962 "8859-8": "iso8859-8",
3964 "euc": "euc-jp-platex",
3969 "iso88595": "iso8859-5",
3970 "iso-8859-7": "iso8859-7",
3972 "jis": "jis-platex",
3974 "l7xenc": "iso8859-13",
3975 "latin1": "iso8859-1",
3976 "latin2": "iso8859-2",
3977 "latin3": "iso8859-3",
3978 "latin4": "iso8859-4",
3979 "latin5": "iso8859-9",
3980 "latin9": "iso8859-15",
3981 "latin10": "iso8859-16",
3982 "SJIS": "shift-jis",
3983 "sjis": "shift-jis-platex",
3986 i = find_token(document.header, "\\inputencoding" , 0)
3989 val = get_value(document.header, "\\inputencoding", i)
3990 if val in list(LaTeX2LyX_enc_dict.keys()):
3991 document.header[i] = "\\inputencoding %s" % LaTeX2LyX_enc_dict[val]
3992 elif val not in known_enc_tuple:
3993 document.warning("Ignoring unknown input encoding: `%s'" % val)
3996 def revert_encodings(document):
3997 """Revert to using the LaTeX names of the encodings instead of the LyX names.
3998 Also revert utf8-platex to sjis, the language default when using Japanese.
4000 LyX2LaTeX_enc_dict = {
4005 "euc-jp-platex": "euc",
4008 "iso8859-1": "latin1",
4009 "iso8859-2": "latin2",
4010 "iso8859-3": "latin3",
4011 "iso8859-4": "latin4",
4012 "iso8859-5": "iso88595",
4013 "iso8859-6": "8859-6",
4014 "iso8859-7": "iso-8859-7",
4015 "iso8859-8": "8859-8",
4016 "iso8859-9": "latin5",
4017 "iso8859-13": "l7xenc",
4018 "iso8859-15": "latin9",
4019 "iso8859-16": "latin10",
4021 "jis-platex": "jis",
4022 "shift-jis": "SJIS",
4023 "shift-jis-platex": "sjis",
4025 "utf8-platex": "sjis"
4027 i = find_token(document.header, "\\inputencoding" , 0)
4030 val = get_value(document.header, "\\inputencoding", i)
4031 if val in list(LyX2LaTeX_enc_dict.keys()):
4032 document.header[i] = "\\inputencoding %s" % LyX2LaTeX_enc_dict[val]
4033 elif val not in known_enc_tuple:
4034 document.warning("Ignoring unknown input encoding: `%s'" % val)
4037 def revert_IEEEtran_3(document):
4039 Reverts Flex Insets to TeX-code
4041 if document.textclass == "IEEEtran":
4047 h = find_token(document.body, "\\begin_inset Flex Author Mark", h)
4049 endh = find_end_of_inset(document.body, h)
4050 document.body[endh - 2 : endh + 1] = put_cmd_in_ert("}")
4051 document.body[h : h + 4] = put_cmd_in_ert("\\IEEEauthorrefmark{")
4054 i = find_token(document.body, "\\begin_inset Flex Author Name", i)
4056 endi = find_end_of_inset(document.body, i)
4057 document.body[endi - 2 : endi + 1] = put_cmd_in_ert("}")
4058 document.body[i : i + 4] = put_cmd_in_ert("\\IEEEauthorblockN{")
4061 j = find_token(document.body, "\\begin_inset Flex Author Affiliation", j)
4063 endj = find_end_of_inset(document.body, j)
4064 document.body[endj - 2 : endj + 1] = put_cmd_in_ert("}")
4065 document.body[j : j + 4] = put_cmd_in_ert("\\IEEEauthorblockA{")
4067 if i == -1 and j == -1 and h == -1:
4071 def revert_kurier_fonts(document):
4072 " Revert kurier font definition to LaTeX "
4074 i = find_token(document.header, "\\font_math", 0)
4076 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
4077 val = get_value(document.header, "\\font_math", i)
4078 if val == "kurier-math":
4079 add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
4080 "\\usepackage[math]{kurier}\n" \
4081 "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
4082 document.header[i] = "\\font_math auto"
4084 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
4085 kurier_fonts = ["kurier", "kurierc", "kurierl", "kurierlc"]
4086 k = find_token(document.header, "\\font_sans kurier", 0)
4088 sf = get_value(document.header, "\\font_sans", k)
4089 if sf in kurier_fonts:
4090 add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
4091 document.header[k] = "\\font_sans default"
4093 def revert_iwona_fonts(document):
4094 " Revert iwona font definition to LaTeX "
4096 i = find_token(document.header, "\\font_math", 0)
4098 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
4099 val = get_value(document.header, "\\font_math", i)
4100 if val == "iwona-math":
4101 add_to_preamble(document, "\\let\\Myrmdefault\\rmdefault\n" \
4102 "\\usepackage[math]{iwona}\n" \
4103 "\\renewcommand{\\rmdefault}{\\Myrmdefault}")
4104 document.header[i] = "\\font_math auto"
4106 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
4107 iwona_fonts = ["iwona", "iwonac", "iwonal", "iwonalc"]
4108 k = find_token(document.header, "\\font_sans iwona", 0)
4110 sf = get_value(document.header, "\\font_sans", k)
4111 if sf in iwona_fonts:
4112 add_to_preamble(document, "\\renewcommand{\\sfdefault}{%s}" % sf)
4113 document.header[k] = "\\font_sans default"
4116 def revert_new_libertines(document):
4117 " Revert new libertine font definition to LaTeX "
4119 if find_token(document.header, "\\use_non_tex_fonts true", 0) != -1:
4122 i = find_token(document.header, "\\font_typewriter libertine-mono", 0)
4124 preamble = "\\usepackage"
4125 sc = find_token(document.header, "\\font_tt_scale", 0)
4127 scval = get_value(document.header, "\\font_tt_scale", sc)
4129 preamble += "[scale=%f]" % (float(scval) / 100)
4130 document.header[sc] = "\\font_tt_scale 100"
4131 preamble += "{libertineMono-type1}"
4132 add_to_preamble(document, [preamble])
4133 document.header[i] = "\\font_typewriter default"
4135 k = find_token(document.header, "\\font_sans biolinum", 0)
4137 preamble = "\\usepackage"
4139 j = find_token(document.header, "\\font_osf true", 0)
4144 sc = find_token(document.header, "\\font_sf_scale", 0)
4146 scval = get_value(document.header, "\\font_sf_scale", sc)
4148 options += ",scale=%f" % (float(scval) / 100)
4149 document.header[sc] = "\\font_sf_scale 100"
4151 preamble += "[" + options +"]"
4152 preamble += "{biolinum-type1}"
4153 add_to_preamble(document, [preamble])
4154 document.header[k] = "\\font_sans default"
4157 def convert_lyxframes(document):
4158 " Converts old beamer frames to new style "
4160 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
4161 if document.textclass not in beamer_classes:
4164 framebeg = ["BeginFrame", "BeginPlainFrame"]
4165 frameend = ["Frame", "PlainFrame", "EndFrame", "BeginFrame", "BeginPlainFrame", "AgainFrame",
4166 "Section", "Section*", "Subsection", "Subsection*", "Subsubsection", "Subsubsection*"]
4167 for lay in framebeg:
4170 i = find_token_exact(document.body, "\\begin_layout " + lay, i)
4173 parent = get_containing_layout(document.body, i)
4174 if parent == False or parent[1] != i:
4175 document.warning("Wrong parent layout!")
4178 frametype = parent[0]
4182 # Step I: Convert ERT arguments
4183 # FIXME: See restrictions in convert_beamerframeargs method
4184 ertend = convert_beamerframeargs(document, i, parbeg)
4187 # Step II: Now rename the layout and convert the title to an argument
4188 j = find_end_of_layout(document.body, i)
4189 document.body[j : j + 1] = ['\\end_layout', '', '\\end_inset', '', '\\end_layout']
4190 if lay == "BeginFrame":
4191 document.body[i] = "\\begin_layout Frame"
4193 document.body[i] = "\\begin_layout PlainFrame"
4194 document.body[ertend + 1 : ertend + 1] = ['\\begin_inset Argument 4',
4195 'status open', '', '\\begin_layout Plain Layout']
4196 # Step III: find real frame end
4199 inInset = get_containing_inset(document.body, i)
4201 fend = find_token(document.body, "\\begin_layout", jj)
4203 document.warning("Malformed LyX document: No real frame end!")
4205 val = get_value(document.body, "\\begin_layout", fend)
4206 if val not in frameend:
4209 # is this frame nested in an inset (e.g., Note)?
4210 if inInset != False:
4211 # if so, end the frame inside the inset
4212 if inInset[2] < fend:
4214 if val == frametype:
4215 document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
4216 # consider explicit EndFrames between two identical frame types
4217 elif val == "EndFrame":
4218 nextlayout = find_token(document.body, "\\begin_layout", fend + 1)
4219 if nextlayout != -1 and get_value(document.body, "\\begin_layout", nextlayout) == frametype:
4220 document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout']
4222 document.body[fend : fend] = ['\\end_deeper']
4224 document.body[fend : fend] = ['\\end_deeper']
4225 document.body[j + 1 : j + 1] = ['', '\\begin_deeper']
4230 def remove_endframes(document):
4231 " Remove deprecated beamer endframes "
4233 beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
4234 if document.textclass not in beamer_classes:
4239 i = find_token_exact(document.body, "\\begin_layout EndFrame", i)
4242 j = find_end_of_layout(document.body, i)
4244 document.warning("Malformed LyX document: Missing \\end_layout to EndFrame")
4247 del document.body[i : j + 1]
4250 def revert_powerdot_flexes(document):
4251 " Reverts powerdot flex insets "
4253 if document.textclass != "powerdot":
4256 flexes = {"Onslide" : "\\onslide",
4257 "Onslide*" : "\\onslide*",
4258 "Onslide+" : "\\onslide+"}
4259 rx = re.compile(r'^\\begin_inset Flex (.+)$')
4263 i = find_token(document.body, "\\begin_inset Flex", i)
4266 m = rx.match(document.body[i])
4268 flextype = m.group(1)
4269 z = find_end_of_inset(document.body, i)
4271 document.warning("Can't find end of Flex " + flextype + " inset.")
4274 if flextype in flexes:
4275 pre = put_cmd_in_ert(flexes[flextype])
4276 arg = find_token(document.body, "\\begin_inset Argument 1", i, z)
4278 argend = find_end_of_inset(document.body, arg)
4280 document.warning("Can't find end of Argument!")
4283 # Find containing paragraph layout
4284 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg)
4285 endPlain = find_end_of_layout(document.body, beginPlain)
4286 argcontent = document.body[beginPlain + 1 : endPlain]
4288 z = z - len(document.body[arg : argend + 1])
4290 del document.body[arg : argend + 1]
4291 pre += put_cmd_in_ert("{") + argcontent + put_cmd_in_ert("}")
4292 pre += put_cmd_in_ert("{")
4293 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4294 endPlain = find_end_of_layout(document.body, beginPlain)
4296 z = z - len(document.body[i : beginPlain + 1])
4298 document.body[i : beginPlain + 1] = pre
4299 post = put_cmd_in_ert("}")
4300 document.body[z - 2 : z + 1] = post
4304 def revert_powerdot_pause(document):
4305 " Reverts powerdot pause layout to ERT "
4307 if document.textclass != "powerdot":
4312 i = find_token(document.body, "\\begin_layout Pause", i)
4315 j = find_end_of_layout(document.body, i)
4317 document.warning("Malformed LyX document: Can't find end of Pause layout")
4321 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\pause")
4322 for p in range(i, j):
4325 arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
4327 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4328 endPlain = find_end_of_layout(document.body, beginPlain)
4329 endInset = find_end_of_inset(document.body, p)
4330 content = document.body[beginPlain + 1 : endPlain]
4332 endlay = endlay - len(document.body[p : endInset + 1])
4334 del document.body[p : endInset + 1]
4335 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4337 document.body[i : i + 1] = subst
4341 def revert_powerdot_itemargs(document):
4342 " Reverts powerdot item arguments to ERT "
4344 if document.textclass != "powerdot":
4348 list_layouts = ["Itemize", "ItemizeType1", "Enumerate", "EnumerateType1"]
4349 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4352 i = find_token(document.body, "\\begin_inset Argument", i)
4355 # Find containing paragraph layout
4356 parent = get_containing_layout(document.body, i)
4358 document.warning("Malformed LyX document: Can't find parent paragraph layout")
4363 realparbeg = parent[3]
4364 layoutname = parent[0]
4366 for p in range(parbeg, parend):
4370 if layoutname in list_layouts:
4371 m = rx.match(document.body[p])
4374 if argnr == "item:1":
4375 j = find_end_of_inset(document.body, i)
4376 # Find containing paragraph layout
4377 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4378 endPlain = find_end_of_layout(document.body, beginPlain)
4379 content = document.body[beginPlain + 1 : endPlain]
4380 del document.body[i:j+1]
4381 subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
4382 document.body[realparbeg : realparbeg] = subst
4383 elif argnr == "item:2":
4384 j = find_end_of_inset(document.body, i)
4385 # Find containing paragraph layout
4386 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
4387 endPlain = find_end_of_layout(document.body, beginPlain)
4388 content = document.body[beginPlain + 1 : endPlain]
4389 del document.body[i:j+1]
4390 subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">")
4391 document.body[realparbeg : realparbeg] = subst
4396 def revert_powerdot_columns(document):
4397 " Reverts powerdot twocolumn to TeX-code "
4398 if document.textclass != "powerdot":
4401 rx = re.compile(r'^\\begin_inset Argument (\S+)$')
4404 i = find_token(document.body, "\\begin_layout Twocolumn", i)
4407 j = find_end_of_layout(document.body, i)
4409 document.warning("Malformed LyX document: Can't find end of Twocolumn layout")
4413 document.body[j : j] = put_cmd_in_ert("}") + document.body[j : j]
4414 endlay += len(put_cmd_in_ert("}"))
4415 subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\twocolumn")
4416 for p in range(i, j):
4419 m = rx.match(document.body[p])
4423 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", p)
4424 endPlain = find_end_of_layout(document.body, beginPlain)
4425 endInset = find_end_of_inset(document.body, p)
4426 content = document.body[beginPlain + 1 : endPlain]
4428 endlay = endlay - len(document.body[p : endInset + 1])
4430 del document.body[p : endInset + 1]
4431 subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]")
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 subst += put_cmd_in_ert("{")
4444 document.body[i : i + 1] = subst
4448 def revert_mbox_fbox(document):
4449 'Convert revert mbox/fbox boxes to TeX-code'
4452 i = find_token(document.body, "\\begin_inset Box", i)
4455 j = find_token(document.body, "width", i)
4457 document.warning("Malformed LyX document: Can't find box width")
4459 width = get_value(document.body, "width", j)
4460 k = find_end_of_inset(document.body, j)
4462 document.warning("Malformed LyX document: Can't find end of box inset")
4465 BeginLayout = find_token(document.body, "\\begin_layout Plain Layout", j)
4466 EndLayout = find_end_of_layout(document.body, BeginLayout)
4467 # replace if width is ""
4469 document.body[EndLayout:k + 1] = put_cmd_in_ert("}")
4470 if document.body[i] == "\\begin_inset Box Frameless":
4471 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\mbox{")
4472 if document.body[i] == "\\begin_inset Box Boxed":
4473 document.body[i:BeginLayout + 1] = put_cmd_in_ert("\\fbox{")
4477 def revert_starred_caption(document):
4478 " Reverts unnumbered longtable caption insets "
4482 i = find_token(document.body, "\\begin_inset Caption LongTableNoNumber", i)
4485 # This is not equivalent, but since the caption inset is a full blown
4486 # text inset a true conversion to ERT is too difficult.
4487 document.body[i] = "\\begin_inset Caption Standard"
4491 def revert_forced_local_layout(document):
4494 i = find_token(document.header, "\\begin_forced_local_layout", i)
4497 j = find_end_of(document.header, i, "\\begin_forced_local_layout", "\\end_forced_local_layout")
4499 # this should not happen
4501 regexp = re.compile(r'\s*forcelocal', re.IGNORECASE)
4502 k = find_re(document.header, regexp, i, j)
4504 del document.header[k]
4506 k = find_re(document.header, regexp, i, j)
4507 k = find_token(document.header, "\\begin_local_layout", 0)
4509 document.header[i] = "\\begin_local_layout"
4510 document.header[j] = "\\end_local_layout"
4512 l = find_end_of(document.header, k, "\\begin_local_layout", "\\end_local_layout")
4514 # this should not happen
4516 lines = document.header[i+1 : j]
4518 document.header[k+1 : k+1] = lines
4519 document.header[i : j ] = []
4521 document.header[i : j ] = []
4522 document.header[k+1 : k+1] = lines
4525 def revert_aa1(document):
4526 " Reverts InsetArguments of aa to TeX-code "
4527 if document.textclass == "aa":
4531 i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4533 revert_Argument_to_TeX_brace(document, i, 0, 1, 4, False, False)
4539 def revert_aa2(document):
4540 " Reverts InsetArguments of aa to TeX-code "
4541 if document.textclass == "aa":
4545 i = find_token(document.body, "\\begin_layout Abstract (structured)", i)
4547 document.body[i] = "\\begin_layout Abstract"
4553 def revert_tibetan(document):
4554 "Set the document language for Tibetan to English"
4556 revert_language(document, "tibetan", "", "tibetan")
4565 # The idea here is that we will have a sequence of chunk paragraphs.
4566 # We want to convert them to paragraphs in one or several chunk insets.
4567 # Individual chunks are terminated by the character @ on the last line.
4568 # This line will be discarded, and following lines are treated as new
4569 # chunks, which go into their own insets.
4570 # The first line of a chunk should look like: <<CONTENT>>=
4571 # We will discard the delimiters, and put the CONTENT into the
4572 # optional argument of the inset, if the CONTENT is non-empty.
4573 def convert_chunks(document):
4574 first_re = re.compile(r'<<(.*)>>=(.*)')
4577 # find start of a block of chunks
4578 i = find_token(document.body, "\\begin_layout Chunk", file_pos)
4584 chunk_started = False
4587 # process the one we just found
4588 j = find_end_of_layout(document.body, i)
4590 document.warning("Malformed LyX documents. Can't find end of Chunk layout!")
4591 # there is no point continuing, as we will run into the same error again.
4593 this_chunk = "".join(document.body[i + 1:j])
4595 # there may be empty lines between chunks
4596 # we just skip them.
4597 if not chunk_started:
4598 if this_chunk != "":
4600 chunk_started = True
4603 contents.append(document.body[i + 1:j])
4605 # look for potential chunk terminator
4606 # on the last line of the chunk paragraph
4607 if document.body[j - 1] == "@":
4610 # look for subsequent chunk paragraph
4611 i = find_token(document.body, "\\begin_layout", j)
4615 if get_value(document.body, "\\begin_layout", i) != "Chunk":
4618 file_pos = end = j + 1
4620 # The last chunk should simply have an "@" in it
4621 # or at least end with "@" (can happen if @ is
4622 # preceded by a newline)
4624 if len(contents) > 0:
4625 lastpar = ''.join(contents[-1])
4626 if not lastpar.endswith("@"):
4627 document.warning("Unexpected chunk content: chunk not terminated by '@'!")
4628 if len(contents) == 0:
4629 # convert empty chunk layouts to Standard
4630 document.body[start] = "\\begin_layout Standard"
4634 # chunk par only contains "@". Just drop it.
4637 # chunk par contains more. Only drop the "@".
4640 # The first line should look like: <<CONTENT>>=
4641 # We want the CONTENT
4642 optarg = ' '.join(contents[0])
4644 # We can already have real chunk content in
4645 # the first par (separated from the options by a newline).
4646 # We collect such stuff to re-insert it later.
4649 match = first_re.search(optarg)
4651 optarg = match.groups()[0]
4652 if match.groups()[1] != "":
4654 for c in contents[0]:
4655 if c.endswith(">>="):
4659 postoptstuff.append(c)
4660 # We have stripped everything. This can be deleted.
4663 newstuff = ['\\begin_layout Standard']
4665 # Maintain paragraph parameters
4666 par_params = ["\\noindent", "\\indent", "\\indent-toggle", "\\leftindent",
4667 "\\start_of_appendix", "\\paragraph_spacing", "\\align",
4668 "\\labelwidthstring"]
4671 if document.body[parms].split(' ', 1)[0] not in par_params:
4673 newstuff.extend([document.body[parms]])
4677 ['\\begin_inset Flex Chunk',
4679 '\\begin_layout Plain Layout', ''])
4681 # If we have a non-empty optional argument, insert it.
4682 if match and optarg != "":
4684 ['\\begin_inset Argument 1',
4686 '\\begin_layout Plain Layout',
4691 # Since we already opened a Plain layout, the first paragraph
4692 # does not need to do that.
4695 # we need to replace newlines with new layouts
4697 started_text = False
4698 for lno in range(0,len(postoptstuff)):
4699 if postoptstuff[lno].startswith("\\begin_inset Newline newline"):
4701 elif start_newline != -1:
4702 if postoptstuff[lno].startswith("\\end_inset"):
4703 # replace that bit, but only if we already have some text
4704 # and we're not at the end except for a blank line
4705 if started_text and \
4706 (lno != len(postoptstuff) - 2 or postoptstuff[-1] != ""):
4707 newstuff.extend(['\\end_layout', '\n', '\\begin_layout Plain Layout', '\n'])
4711 newstuff.extend([postoptstuff[lno]])
4712 newstuff.append('\\end_layout')
4716 newstuff.extend(['', '\\begin_layout Plain Layout', ''])
4720 newstuff.append('\\end_layout')
4722 newstuff.extend(['', '\\end_inset', '', '\\end_layout', ''])
4724 document.body[start:end] = newstuff
4726 file_pos += len(newstuff) - (end - start)
4729 def revert_chunks(document):
4732 i = find_token(document.body, "\\begin_inset Flex Chunk", i)
4736 iend = find_end_of_inset(document.body, i)
4738 document.warning("Can't find end of Chunk!")
4742 # Look for optional argument
4744 ostart = find_token(document.body, "\\begin_inset Argument 1", i, iend)
4746 oend = find_end_of_inset(document.body, ostart)
4747 k = find_token(document.body, "\\begin_layout Plain Layout", ostart, oend)
4749 document.warning("Malformed LyX document: Can't find argument contents!")
4751 m = find_end_of_layout(document.body, k)
4752 optarg = "".join(document.body[k+1:m])
4754 # We now remove the optional argument, so we have something
4755 # uniform on which to work
4756 document.body[ostart : oend + 1] = []
4757 # iend is now invalid
4758 iend = find_end_of_inset(document.body, i)
4760 retval = get_containing_layout(document.body, i)
4762 document.warning("Can't find containing layout for Chunk!")
4765 (lname, lstart, lend, pstart) = retval
4766 # we now want to work through the various paragraphs, and collect their contents
4770 k = find_token(document.body, "\\begin_layout Plain Layout", k, lend)
4773 j = find_end_of_layout(document.body, k)
4775 document.warning("Can't find end of layout inside chunk!")
4777 parlist.append(document.body[k+1:j])
4779 # we now need to wrap all of these paragraphs in chunks
4781 newlines.extend(["\\begin_layout Chunk", "", "<<" + optarg + ">>=", "\\end_layout", ""])
4782 for stuff in parlist:
4783 newlines.extend(["\\begin_layout Chunk"] + stuff + ["\\end_layout", ""])
4784 newlines.extend(["\\begin_layout Chunk", "", "@", "\\end_layout", ""])
4785 # replace old content with new content
4786 document.body[lstart : lend + 1] = newlines
4787 i = lstart + len(newlines)
4794 supported_versions = ["2.1.0","2.1"]
4797 [415, [convert_undertilde]],
4799 [417, [convert_japanese_encodings]],
4800 [418, [convert_justification]],
4802 [420, [convert_biblio_style]],
4803 [421, [convert_longtable_captions]],
4804 [422, [convert_use_packages]],
4805 [423, [convert_use_mathtools]],
4806 [424, [convert_cite_engine_type]],
4807 # No convert_cancel, since cancel will be loaded automatically
4808 # in format 425 without any possibility to switch it off.
4809 # This has been fixed in format 464.
4813 [428, [convert_cell_rotation]],
4814 [429, [convert_table_rotation]],
4815 [430, [convert_listoflistings]],
4816 [431, [convert_use_amssymb]],
4818 [433, [convert_armenian]],
4825 [440, [convert_mathfonts]],
4826 [441, [convert_mdnomath]],
4831 [446, [convert_latexargs]],
4832 [447, [convert_IEEEtran, convert_AASTeX, convert_AGUTeX, convert_IJMP, convert_SIGPLAN, convert_SIGGRAPH, convert_EuropeCV, convert_Initials, convert_ModernCV]],
4833 [448, [convert_literate]],
4836 [451, [convert_beamerargs, convert_againframe_args, convert_corollary_args, convert_quote_args]],
4837 [452, [convert_beamerblocks]],
4838 [453, [convert_use_stmaryrd]],
4839 [454, [convert_overprint]],
4841 [456, [convert_epigraph]],
4842 [457, [convert_use_stackrel]],
4843 [458, [convert_captioninsets, convert_captionlayouts]],
4848 [463, [convert_encodings]],
4849 [464, [convert_use_cancel]],
4850 [465, [convert_lyxframes, remove_endframes]],
4856 [471, [convert_cite_engine_type_default]],
4859 [474, [convert_chunks, cleanup_beamerargs]],
4863 [473, [revert_chunks]],
4864 [472, [revert_tibetan]],
4865 [471, [revert_aa1,revert_aa2]],
4866 [470, [revert_cite_engine_type_default]],
4867 [469, [revert_forced_local_layout]],
4868 [468, [revert_starred_caption]],
4869 [467, [revert_mbox_fbox]],
4870 [466, [revert_iwona_fonts]],
4871 [465, [revert_powerdot_flexes, revert_powerdot_pause, revert_powerdot_itemargs, revert_powerdot_columns]],
4873 [463, [revert_use_cancel]],
4874 [462, [revert_encodings]],
4875 [461, [revert_new_libertines]],
4876 [460, [revert_kurier_fonts]],
4877 [459, [revert_IEEEtran_3]],
4878 [458, [revert_fragileframe, revert_newframes]],
4879 [457, [revert_captioninsets, revert_captionlayouts]],
4880 [456, [revert_use_stackrel]],
4881 [455, [revert_epigraph]],
4882 [454, [revert_frametitle]],
4883 [453, [revert_overprint]],
4884 [452, [revert_use_stmaryrd]],
4885 [451, [revert_beamerblocks]],
4886 [450, [revert_beamerargs, revert_beamerargs2, revert_beamerargs3, revert_beamerflex]],
4887 [449, [revert_garamondx, revert_garamondx_newtxmath]],
4888 [448, [revert_itemargs]],
4889 [447, [revert_literate]],
4890 [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]],
4891 [445, [revert_latexargs]],
4892 [444, [revert_uop]],
4893 [443, [revert_biolinum]],
4895 [441, [revert_newtxmath]],
4896 [440, [revert_mdnomath]],
4897 [439, [revert_mathfonts]],
4898 [438, [revert_minionpro]],
4899 [437, [revert_ipadeco, revert_ipachar]],
4900 [436, [revert_texgyre]],
4901 [435, [revert_mathdesign]],
4902 [434, [revert_txtt]],
4903 [433, [revert_libertine]],
4904 [432, [revert_armenian]],
4905 [431, [revert_languages, revert_ancientgreek]],
4906 [430, [revert_use_amssymb]],
4907 [429, [revert_listoflistings]],
4908 [428, [revert_table_rotation]],
4909 [427, [revert_cell_rotation]],
4910 [426, [revert_tipa]],
4911 [425, [revert_verbatim]],
4912 [424, [revert_cancel]],
4913 [423, [revert_cite_engine_type]],
4914 [422, [revert_use_mathtools]],
4915 [421, [revert_use_packages]],
4916 [420, [revert_longtable_captions]],
4917 [419, [revert_biblio_style]],
4918 [418, [revert_australian]],
4919 [417, [revert_justification]],
4920 [416, [revert_japanese_encodings]],
4921 [415, [revert_negative_space, revert_math_spaces]],
4922 [414, [revert_undertilde]],
4923 [413, [revert_visible_space]]
4927 if __name__ == "__main__":