X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=lib%2Flyx2lyx%2Flyx_2_1.py;h=f4d7398f04c6847dcb4efc1d2e0b983b7577a74e;hb=9a0d70a45fde2d2a5d7af84f39f91e3c2ea91dff;hp=5dafc8ab0d0b64513ef4a8f4ce4c86e9a5954d77;hpb=50066b46ab7f7a1089dbeb687a00c1d75ca90919;p=lyx.git diff --git a/lib/lyx2lyx/lyx_2_1.py b/lib/lyx2lyx/lyx_2_1.py index 5dafc8ab0d..f4d7398f04 100644 --- a/lib/lyx2lyx/lyx_2_1.py +++ b/lib/lyx2lyx/lyx_2_1.py @@ -28,7 +28,7 @@ import sys, os from parser_tools import count_pars_in_inset, del_token, find_token, find_token_exact, \ find_token_backwards, find_end_of, find_end_of_inset, find_end_of_layout, \ find_end_of_sequence, find_re, get_option_value, get_containing_layout, \ - get_value, get_quoted_value, set_option_value + get_containing_inset, get_value, get_quoted_value, set_option_value #from parser_tools import find_token, find_end_of, find_tokens, \ #find_end_of_inset, find_end_of_layout, \ @@ -120,21 +120,28 @@ def convert_TeX_brace_to_Argument(document, line, n, nmax, inset, environment, o Todo: this routine can currently handle only one mandatory argument of environments ''' + + end_layout = find_end_of_layout(document.body, line) lineERT = line endn = line loop = 1 - while lineERT != -1 and n < nmax + 1: - lineERT = find_token(document.body, "\\begin_inset ERT", lineERT) - if environment == False and lineERT != -1: - bracePair = -1 + while n < nmax + 1: + lineERT = find_token(document.body, "\\begin_inset ERT", lineERT, end_layout) + if lineERT == -1: + break + if environment == False: + end_ERT = find_end_of_inset(document.body, lineERT) + if end_ERT == -1: + document.warning("Can't find end of ERT!!") + break + # Note that this only checks for ][ or }{ at the beginning of a line if opt: - bracePair = find_token(document.body, "][", lineERT) + bracePair = find_token(document.body, "][", lineERT, end_ERT) else: - bracePair = find_token(document.body, "}{", lineERT) - # assure that the "}{" is in this ERT - if bracePair == lineERT + 5: + bracePair = find_token(document.body, "}{", lineERT, end_ERT) + if bracePair != -1: end = find_token(document.body, "\\end_inset", bracePair) - document.body[lineERT : end + 1] = ["\\end_layout", "", "\\end_inset"] + document.body[lineERT : end_ERT + 1] = ["\\end_layout", "", "\\end_inset"] if loop == 1: # in the case that n > 1 we have optional arguments before # therefore detect them if any @@ -156,24 +163,23 @@ def convert_TeX_brace_to_Argument(document, line, n, nmax, inset, environment, o document.body[line + 1 : line + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"] else: document.body[line + 4 : line + 4] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"] - else: + else: # if loop != 1 document.body[endn : endn] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"] n += 1 endn = end - loop = loop + 1 - # now check the case that we have "}" + "{" in two ERTs - else: - endBrace = -1 + loop += 1 + else: + # no brace pair found + # now check the case that we have "}" + "{" in two ERTs if opt: - endBrace = find_token(document.body, "]", lineERT) + endBrace = find_token(document.body, "]", lineERT, end_layout) else: - endBrace = find_token(document.body, "}", lineERT) + endBrace = find_token(document.body, "}", lineERT, end_layout) if endBrace == lineERT + 5: - beginBrace = -1 if opt: - beginBrace = find_token(document.body, "[", endBrace) + beginBrace = find_token(document.body, "[", endBrace, end_layout) else: - beginBrace = find_token(document.body, "{", endBrace) + beginBrace = find_token(document.body, "{", endBrace, end_layout) # assure that the ERTs are consecutive (11 or 12 depending if there is a space between the ERTs or not) if beginBrace == endBrace + 11 or beginBrace == endBrace + 12: end = find_token(document.body, "\\end_inset", beginBrace) @@ -212,27 +218,42 @@ def convert_TeX_brace_to_Argument(document, line, n, nmax, inset, environment, o lineERT += 1 else: lineERT += 1 - if environment == True and lineERT != -1: - opening = -1 + if environment == True: + end_ERT = find_end_of_inset(document.body, lineERT) + if end_ERT == -1: + document.warning("Can't find end of ERT!!") + break + # Note that this only checks for [ or { at the beginning of a line if opt: - opening = find_token(document.body, "[", lineERT) + opening = find_token(document.body, "[", lineERT, end_ERT) else: - opening = find_token(document.body, "{", lineERT) - if opening == lineERT + 5: # assure that the "{" is in this ERT - end = find_token(document.body, "\\end_inset", opening) - document.body[lineERT : end + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"] - n += 1 - lineERT2 = find_token(document.body, "\\begin_inset ERT", lineERT) - closing = -1 - if opt: - closing = find_token(document.body, "]", lineERT) + opening = find_token(document.body, "{", lineERT, end_ERT) + if opening != -1: + lineERT2 = find_token(document.body, "\\begin_inset ERT", end_ERT, end_layout) + if lineERT2 == -1: + # argument in a single ERT + # strip off the opening bracket + document.body[opening] = document.body[opening][1:] + ertcontlastline = end_ERT - 3 + if (opt and document.body[ertcontlastline].endswith("]")) or document.body[ertcontlastline].endswith("}"): + # strip off the closing bracket + document.body[ertcontlastline] = document.body[ertcontlastline][:-1] + end2 = find_token(document.body, "\\end_inset", ertcontlastline) + document.body[lineERT : lineERT + 1] = ["\\begin_inset Argument " + str(n)] else: - closing = find_token(document.body, "}", lineERT2) - if closing == lineERT2 + 5: # assure that the "}" is in this ERT - end2 = find_token(document.body, "\\end_inset", closing) - document.body[lineERT2 : end2 + 1] = ["\\end_layout", "", "\\end_inset"] - else: - lineERT += 1 + end_ERT2 = find_end_of_inset(document.body, lineERT2) + if end_ERT2 == -1: + document.warning("Can't find end of second ERT!!") + break + if opt: + closing = find_token(document.body, "]", lineERT2, end_ERT2) + else: + closing = find_token(document.body, "}", lineERT2, end_ERT2) + if closing != -1: # assure that the "}" is in this ERT + end2 = find_token(document.body, "\\end_inset", closing) + document.body[lineERT2 : end2 + 1] = ["\\end_layout", "", "\\end_inset"] + document.body[lineERT : end_ERT + 1] = ["\\begin_inset Argument " + str(n), "status open", "", "\\begin_layout Plain Layout"] + n += 1 ############################################################################### @@ -253,6 +274,7 @@ def revert_visible_space(document): document.body[i:end + 1] = subst +undertilde_commands = ["utilde"] def convert_undertilde(document): " Load undertilde automatically " i = find_token(document.header, "\\use_mathdots" , 0) @@ -264,52 +286,60 @@ def convert_undertilde(document): document.warning("Malformed LyX document: Can't find \\use_mathdots.") return; j = find_token(document.preamble, "\\usepackage{undertilde}", 0) - if j == -1: - document.header.insert(i + 1, "\\use_undertilde 0") - else: - document.header.insert(i + 1, "\\use_undertilde 2") + if j != -1: + # package was loaded in the preamble, convert this to header setting for round trip + document.header.insert(i + 1, "\\use_undertilde 2") # on del document.preamble[j] + else: + j = 0 + while True: + j = find_token(document.body, '\\begin_inset Formula', j) + if j == -1: + break + k = find_end_of_inset(document.body, j) + if k == -1: + document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(j)) + j += 1 + continue + code = "\n".join(document.body[j:k]) + for c in undertilde_commands: + if code.find("\\%s" % c) != -1: + # at least one of the commands was found - need to switch package off + document.header.insert(i + 1, "\\use_undertilde 0") # off + return + j = k + # no command was found - set to auto (bug 9069) + document.header.insert(i + 1, "\\use_undertilde 1") # auto + def revert_undertilde(document): " Load undertilde if used in the document " - undertilde = find_token(document.header, "\\use_undertilde" , 0) - if undertilde == -1: - document.warning("No \\use_undertilde line. Assuming auto.") - else: - val = get_value(document.header, "\\use_undertilde", undertilde) - del document.header[undertilde] - try: - usetilde = int(val) - except: - document.warning("Invalid \\use_undertilde value: " + val + ". Assuming auto.") - # probably usedots has not been changed, but be safe. - usetilde = 1 - - if usetilde == 0: - # do not load case - return - if usetilde == 2: - # force load case + regexp = re.compile(r'(\\use_undertilde)') + i = find_re(document.header, regexp, 0) + value = "1" # default is auto + if i != -1: + value = get_value(document.header, "\\use_undertilde" , i).split()[0] + del document.header[i] + if value == "2": # on add_to_preamble(document, ["\\usepackage{undertilde}"]) - return - - # so we are in the auto case. we want to load undertilde if \utilde is used. - i = 0 - while True: - i = find_token(document.body, '\\begin_inset Formula', i) - if i == -1: - return - j = find_end_of_inset(document.body, i) - if j == -1: - document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i)) - i += 1 - continue - code = "\n".join(document.body[i:j]) - if code.find("\\utilde") != -1: - add_to_preamble(document, ["\\@ifundefined{utilde}{\\usepackage{undertilde}}"]) - return - i = j + elif value == "1": # auto + i = 0 + while True: + i = find_token(document.body, '\\begin_inset Formula', i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i)) + i += 1 + continue + code = "\n".join(document.body[i:j]) + for c in undertilde_commands: + if code.find("\\%s" % c) != -1: + add_to_preamble(document, ["\\usepackage{undertilde}"]) + return + i = j def revert_negative_space(document): @@ -368,7 +398,7 @@ def convert_japanese_encodings(document): if i == -1: return val = get_value(document.header, "\\inputencoding", i) - if val in jap_enc_dict.keys(): + if val in list(jap_enc_dict.keys()): document.header[i] = "\\inputencoding %s" % jap_enc_dict[val] @@ -383,10 +413,25 @@ def revert_japanese_encodings(document): if i == -1: return val = get_value(document.header, "\\inputencoding", i) - if val in jap_enc_dict.keys(): + if val in list(jap_enc_dict.keys()): document.header[i] = "\\inputencoding %s" % jap_enc_dict[val] +def convert_justification(document): + " Add the \\justification buffer param" + i = find_token(document.header, "\\suppress_date" , 0) + if i == -1: + i = find_token(document.header, "\\paperorientation" , 0) + if i == -1: + i = find_token(document.header, "\\use_indices" , 0) + if i == -1: + i = find_token(document.header, "\\use_bibtopic" , 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\suppress_date.") + return + document.header.insert(i + 1, "\\justification true") + + def revert_justification(document): " Revert the \\justification buffer param" if not del_token(document.header, '\\justification', 0): @@ -537,32 +582,73 @@ def convert_use_packages(document): def revert_use_packages(document): "use_package xxx yyy => use_xxx yyy" - packages = ["amsmath", "esint", "mathdots", "mhchem", "undertilde"] + packages = ["amsmath", "esint", "mhchem", "mathdots", "undertilde"] # the order is arbitrary for the use_package version, and not all packages need to be given. # Ensure a complete list and correct order (important for older LyX versions and especially lyx2lyx) - j = 0 + # first loop: find line with first package + j = -1 + for p in packages: + regexp = re.compile(r'(\\use_package\s+%s)' % p) + i = find_re(document.header, regexp, 0) + if i != -1 and (j < 0 or i < j): + j = i + # second loop: replace or insert packages in front of all existing ones for p in packages: regexp = re.compile(r'(\\use_package\s+%s)' % p) - i = find_re(document.header, regexp, j) + i = find_re(document.header, regexp, 0) if i != -1: value = get_value(document.header, "\\use_package %s" % p, i).split()[1] del document.header[i] - j = i - document.header.insert(j, "\\use_%s %s" % (p, value)) + document.header.insert(j, "\\use_%s %s" % (p, value)) + else: + document.header.insert(j, "\\use_%s 1" % p) j += 1 -def convert_use_package(document, pkg): +def convert_use_package(document, pkg, commands, oldauto): + # oldauto defines how the version we are converting from behaves: + # if it is true, the old version uses the package automatically. + # if it is false, the old version never uses the package. i = find_token(document.header, "\\use_package", 0) if i == -1: document.warning("Malformed LyX document: Can't find \\use_package.") return; j = find_token(document.preamble, "\\usepackage{" + pkg + "}", 0) - if j == -1: - document.header.insert(i + 1, "\\use_package " + pkg + " 0") - else: - document.header.insert(i + 1, "\\use_package " + pkg + " 2") + if j != -1: + # package was loaded in the preamble, convert this to header setting for round trip + document.header.insert(i + 1, "\\use_package " + pkg + " 2") # on del document.preamble[j] + # If oldauto is true we have two options: + # We can either set the package to auto - this is correct for files in + # format 425 to 463, and may create a conflict for older files which use + # any command in commands with a different definition. + # Or we can look whether any command in commands is used, and set it to + # auto if not and to off if yes. This will not create a conflict, but will + # create uncompilable documents for files in format 425 to 463, which use + # any command in commands. + # We choose the first option since its error is less likely. + elif oldauto: + document.header.insert(i + 1, "\\use_package " + pkg + " 1") # auto + else: + j = 0 + while True: + j = find_token(document.body, '\\begin_inset Formula', j) + if j == -1: + break + k = find_end_of_inset(document.body, j) + if k == -1: + document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(j)) + j += 1 + continue + code = "\n".join(document.body[j:k]) + for c in commands: + if code.find("\\%s" % c) != -1: + # at least one of the commands was found - need to switch package off + document.header.insert(i + 1, "\\use_package " + pkg + " 0") # off + return + j = k + # no command was found - set to auto (bug 9069) + document.header.insert(i + 1, "\\use_package " + pkg + " 1") # auto def revert_use_package(document, pkg, commands, oldauto): @@ -596,31 +682,24 @@ def revert_use_package(document, pkg, commands, oldauto): i = j -def convert_use_mathtools(document): - "insert use_package mathtools" - convert_use_package(document, "mathtools") - - -def revert_use_mathtools(document): - "remove use_package mathtools" - commands = ["mathclap", "mathllap", "mathrlap", \ +mathtools_commands = ["mathclap", "mathllap", "mathrlap", \ "lgathered", "rgathered", "vcentcolon", "dblcolon", \ "coloneqq", "Coloneqq", "coloneq", "Coloneq", "eqqcolon", \ "Eqqcolon", "eqcolon", "Eqcolon", "colonapprox", \ "Colonapprox", "colonsim", "Colonsim"] - revert_use_package(document, "mathtools", commands, False) +def convert_use_mathtools(document): + "insert use_package mathtools" + convert_use_package(document, "mathtools", mathtools_commands, False) -def convert_use_stmaryrd(document): - "insert use_package stmaryrd" - convert_use_package(document, "stmaryrd") +def revert_use_mathtools(document): + "remove use_package mathtools" + revert_use_package(document, "mathtools", mathtools_commands, False) -def revert_use_stmaryrd(document): - "remove use_package stmaryrd" - # commands provided by stmaryrd.sty but LyX uses other packages: - # boxdot lightning, bigtriangledown, bigtriangleup - commands = ["shortleftarrow", "shortrightarrow", "shortuparrow", \ +# commands provided by stmaryrd.sty but LyX uses other packages: +# boxdot lightning, bigtriangledown, bigtriangleup +stmaryrd_commands = ["shortleftarrow", "shortrightarrow", "shortuparrow", \ "shortdownarrow", "Yup", "Ydown", "Yleft", "Yright", \ "varcurlyvee", "varcurlywedge", "minuso", "baro", \ "sslash", "bbslash", "moo", "varotimes", "varoast", \ @@ -651,19 +730,25 @@ def revert_use_stmaryrd(document): "varcopyright", "longarrownot", "Longarrownot", \ "Mapsto", "mapsfrom", "Mapsfrom" "Longmapsto", \ "longmapsfrom", "Longmapsfrom"] - revert_use_package(document, "stmaryrd", commands, False) +def convert_use_stmaryrd(document): + "insert use_package stmaryrd" + convert_use_package(document, "stmaryrd", stmaryrd_commands, False) +def revert_use_stmaryrd(document): + "remove use_package stmaryrd" + revert_use_package(document, "stmaryrd", stmaryrd_commands, False) + +stackrel_commands = ["stackrel"] def convert_use_stackrel(document): "insert use_package stackrel" - convert_use_package(document, "stackrel") + convert_use_package(document, "stackrel", stackrel_commands, False) def revert_use_stackrel(document): "remove use_package stackrel" - commands = ["stackrel"] - revert_use_package(document, "stackrel", commands, False) + revert_use_package(document, "stackrel", stackrel_commands, False) def convert_cite_engine_type(document): @@ -722,11 +807,11 @@ def revert_cite_engine_type_default(document): document.header[i] = "\\cite_engine_type " + engine_type +cancel_commands = ["cancel", "bcancel", "xcancel", "cancelto"] # this is the same, as revert_use_cancel() except for the default def revert_cancel(document): "add cancel to the preamble if necessary" - commands = ["cancelto", "cancel", "bcancel", "xcancel"] - revert_use_package(document, "cancel", commands, False) + revert_use_package(document, "cancel", cancel_commands, False) def revert_verbatim(document): @@ -741,10 +826,11 @@ def revert_verbatim(document): '\\end_layout', '', '\\end_inset', '', '', '\\end_layout'] subst_begin = ['\\begin_layout Standard', '\\noindent', - '\\begin_inset ERT', 'status collapsed', '', + '\\begin_inset ERT', 'status open', '', '\\begin_layout Plain Layout', '', '', '\\backslash', 'begin{verbatim}', '\\end_layout', '', '\\begin_layout Plain Layout', ''] + while 1: i = find_token(document.body, "\\begin_layout Verbatim", i) if i == -1: @@ -757,16 +843,17 @@ def revert_verbatim(document): # delete all line breaks insets (there are no other insets) l = i while 1: - n = find_token(document.body, "\\begin_inset Newline newline", l) + n = find_token(document.body, "\\begin_inset Newline newline", l, j) if n == -1: - n = find_token(document.body, "\\begin_inset Newline linebreak", l) + n = find_token(document.body, "\\begin_inset Newline linebreak", l, j) if n == -1: break m = find_end_of_inset(document.body, n) del(document.body[m:m+1]) document.body[n:n+1] = ['\end_layout', '', '\\begin_layout Plain Layout'] l += 1 - j += 1 + # we deleted a line, so the end of the inset moved forward. + j -= 1 # consecutive verbatim environments need to be connected k = find_token(document.body, "\\begin_layout Verbatim", j) if k == j + 2 and consecutive == False: @@ -851,7 +938,7 @@ def revert_cell_rotation(document): document.body[i] = rgx.sub('', document.body[i]) elif value == "90": rgx = re.compile(r' rotate="[^"]+?"') - document.body[i] = rgx.sub('rotate="true"', document.body[i]) + document.body[i] = rgx.sub(' rotate="true"', document.body[i]) else: rgx = re.compile(r' rotate="[^"]+?"') load_rotating = True @@ -1028,13 +1115,12 @@ def revert_use_amssymb(document): def convert_use_cancel(document): "insert use_package cancel" - convert_use_package(document, "cancel") + convert_use_package(document, "cancel", cancel_commands, True) def revert_use_cancel(document): "remove use_package cancel" - commands = ["cancel", "bcancel", "xcancel", "cancelto"] - revert_use_package(document, "cancel", commands, True) + revert_use_package(document, "cancel", cancel_commands, True) def revert_ancientgreek(document): @@ -1141,7 +1227,7 @@ def revert_mathdesign(document): if i == -1: return val = get_value(document.header, "\\font_roman", i) - if val in mathdesign_dict.keys(): + if val in list(mathdesign_dict.keys()): preamble = "\\usepackage[%s" % mathdesign_dict[val] expert = False j = find_token(document.header, "\\font_osf true", 0) @@ -1305,7 +1391,7 @@ def revert_mathfonts(document): k = find_token(document.header, "\\font_osf true", 0) if k != -1: rm += "-osf" - if rm in mathfont_dict.keys(): + if rm in list(mathfont_dict.keys()): add_to_preamble(document, mathfont_dict[rm]) document.header[j] = "\\font_roman default" if k != -1: @@ -1326,7 +1412,7 @@ def revert_mdnomath(document): if i == -1: return val = get_value(document.header, "\\font_roman", i) - if val in mathdesign_dict.keys(): + if val in list(mathdesign_dict.keys()): j = find_token(document.header, "\\font_math", 0) if j == -1: document.header[i] = "\\font_roman %s" % mathdesign_dict[val] @@ -1351,7 +1437,7 @@ def convert_mdnomath(document): if i == -1: return val = get_value(document.header, "\\font_roman", i) - if val in mathdesign_dict.keys(): + if val in list(mathdesign_dict.keys()): document.header[i] = "\\font_roman %s" % mathdesign_dict[val] @@ -1368,7 +1454,7 @@ def revert_newtxmath(document): "minion-ntxm": "\\usepackage[minion]{newtxmath}", "newtxmath": "\\usepackage{newtxmath}", } - if val in mathfont_dict.keys(): + if val in list(mathfont_dict.keys()): add_to_preamble(document, mathfont_dict[val]) document.header[i] = "\\font_math auto" @@ -1431,9 +1517,9 @@ def convert_latexargs(document): "svglobal3", "svglobal", "svjog", "svmono", "svmult", "svprobth", "tarticle", "tbook", "treport", "tufte-book", "tufte-handout"] # A list of "safe" modules, same as above - safe_modules = ["biblatex", "beameraddons", "beamersession", "braille", "customHeadersFooters", - "endnotes", "enumitem", "eqs-within-sections", "figs-within-sections", "fix-cm", - "fixltx2e", "foottoend", "hanging", "jscharstyles", "knitr", "lilypond", + safe_modules = ["biblatex", "beameraddons", "beamer-resenumerate", "beamersession", "braille", + "customHeadersFooters", "endnotes", "enumitem", "eqs-within-sections", "figs-within-sections", + "fix-cm", "fixltx2e", "foottoend", "hanging", "jscharstyles", "knitr", "lilypond", "linguistics", "linguisticx", "logicalmkup", "minimalistic", "nomindex", "noweb", "pdfcomment", "sweave", "tabs-within-sections", "theorems-ams-bytype", "theorems-ams-extended-bytype", "theorems-ams-extended", "theorems-ams", "theorems-bytype", @@ -1514,7 +1600,7 @@ def convert_latexargs(document): if argnr > allowed_opts and argnr < first_req: argnr = first_req document.body[p] = "\\begin_inset Argument %d" % argnr - i += 1 + i = parend + 1 def revert_latexargs(document): @@ -1541,12 +1627,18 @@ def revert_latexargs(document): continue parbeg = parent[1] parend = parent[2] - realparbeg = parent[3] - # Collect all arguments in this paragraph + # Do not set realparbeg to parent[3], since this does not work if we + # have another inset (e.g. label or index) before the first argument + # inset (this is the case in the user guide of LyX 2.0.8) + realparbeg = -1 + # Collect all arguments in this paragraph realparend = parend for p in range(parbeg, parend): m = rx.match(document.body[p]) if m: + if realparbeg < 0: + # This is the first argument inset + realparbeg = p val = int(m.group(1)) j = find_end_of_inset(document.body, p) # Revert to old syntax @@ -1562,8 +1654,11 @@ def revert_latexargs(document): del document.body[p : j + 1] if p >= realparend: break + if realparbeg < 0: + # No argument inset found + realparbeg = parent[3] # Now sort the arg insets - subst = [""] + subst = [] for f in sorted(args): subst += args[f] del args[f] @@ -2334,34 +2429,65 @@ def convert_corollary_args(document): parbeg = parent[3] if i != -1: if document.body[parbeg] == "\\begin_inset ERT": - ertcont = parbeg + 5 - if document.body[ertcont].startswith("<"): + ertcontfirstline = parbeg + 5 + # Find the last ERT in this paragraph (which might also be the first) + lastertbeg = find_token_backwards(document.body, "\\begin_inset ERT", j) + if lastertbeg == -1: + document.warning("Last ERT not found!") + break + lastertend = find_end_of_inset(document.body, lastertbeg) + if lastertend == -1: + document.warning("End of last ERT not found!") + break + ertcontlastline = lastertend - 3 + if document.body[ertcontfirstline].startswith("<"): # This is an overlay specification # strip off the < - document.body[ertcont] = document.body[ertcont][1:] - if document.body[ertcont].endswith(">"): + document.body[ertcontfirstline] = document.body[ertcontfirstline][1:] + if document.body[ertcontlastline].endswith(">"): # strip off the > - document.body[ertcont] = document.body[ertcont][:-1] - elif document.body[ertcont].endswith("]"): + document.body[ertcontlastline] = document.body[ertcontlastline][:-1] + if ertcontfirstline < ertcontlastline: + # Multiline ERT. Might contain TeX code. Embrace in ERT. + document.body[ertcontlastline : ertcontlastline + 1] = [ + document.body[ertcontlastline], '\\end_layout', '', '\\end_inset'] + document.body[ertcontfirstline : ertcontfirstline + 1] = [ + '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1', + 'status collapsed', '', '\\begin_layout Plain Layout', + '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout', + document.body[ertcontfirstline]] + else: + # Convert to ArgInset + document.body[parbeg] = "\\begin_inset Argument 1" + elif document.body[ertcontlastline].endswith("]"): # divide the args - tok = document.body[ertcont].find('>[') - if tok != -1: - subst = [document.body[ertcont][:tok], - '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2', - 'status collapsed', '', '\\begin_layout Plain Layout', - document.body[ertcont][tok + 2:-1]] - document.body[ertcont : ertcont + 1] = subst - # Convert to ArgInset - document.body[parbeg] = "\\begin_inset Argument 1" + ertcontdivline = document.body[ertcontfirstline].find('>[') + if ertcontdivline != -1: + if ertcontfirstline < ertcontlastline: + # Multiline ERT. Might contain TeX code. Embrace in ERT. + document.body[ertcontlastline : ertcontlastline + 1] = [ + document.body[ertcontlastline], '\\end_layout', '', '\\end_inset'] + document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok], + '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2', + 'status collapsed', '', '\\begin_layout Plain Layout', + '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout', + document.body[ertcontdivline][tok + 2:]] + else: + document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok], + '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2', + 'status collapsed', '', '\\begin_layout Plain Layout', + document.body[ertcontdivline][tok + 2:]] + # Convert to ArgInset + document.body[parbeg] = "\\begin_inset Argument 1" i = j continue - elif document.body[ertcont].startswith("["): - if document.body[ertcont].endswith("]"): + elif document.body[ertcontlastline].startswith("["): + if document.body[ertcontlastline].endswith("]"): # This is an ERT option # strip off the [ - document.body[ertcont] = document.body[ertcont][1:] + document.body[ertcontlastline] = document.body[ertcontlastline][1:] # strip off the ] - document.body[ertcont] = document.body[ertcont][:-1] + document.body[ertcontlastline] = document.body[ertcontlastline][:-1] # Convert to ArgInset document.body[parbeg] = "\\begin_inset Argument 2" else: @@ -2405,6 +2531,42 @@ def convert_quote_args(document): i = j +def cleanup_beamerargs(document): + " Clean up empty ERTs (conversion artefacts) " + + beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"] + if document.textclass not in beamer_classes: + return + + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Argument", i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of Argument inset") + i += 1 + continue + while True: + ertbeg = find_token(document.body, "\\begin_inset ERT", i, j) + if ertbeg == -1: + break + ertend = find_end_of_inset(document.body, ertbeg) + if ertend == -1: + document.warning("Malformed LyX document: Can't find end of ERT inset") + break + stripped = [line for line in document.body[ertbeg : ertend + 1] if line.strip()] + if len(stripped) == 5: + # This is an empty ERT + offset = len(document.body[ertbeg : ertend + 1]) + del document.body[ertbeg : ertend + 1] + j = j - offset + else: + i = ertend + i += 1 + + def revert_beamerargs(document): " Reverts beamer arguments to old layout " @@ -2543,8 +2705,22 @@ def revert_beamerargs(document): endPlain = find_end_of_layout(document.body, beginPlain) content = document.body[beginPlain + 1 : endPlain] del document.body[i:j+1] - subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]") - document.body[realparbeg : realparbeg] = subst + if layoutname == "Description": + # Description only has one (overlay) item arg + subst = put_cmd_in_ert("<") + content + put_cmd_in_ert(">") + # This must be put after the first space (begin of decription body + # in LyX's arkward description list syntax) + # Try to find that place ... + rxx = re.compile(r'^([^\\ ]+ )(.*)$') + for q in range(parbeg, parend): + m = rxx.match(document.body[q]) + if m: + # We found it. Now insert the ERT argument just there: + document.body[q : q] = [m.group(1), ''] + subst + ['', m.group(2)] + break + else: + subst = put_cmd_in_ert("[") + content + put_cmd_in_ert("]") + document.body[realparbeg : realparbeg] = subst elif argnr == "item:2": j = find_end_of_inset(document.body, i) # Find containing paragraph layout @@ -2904,43 +3080,219 @@ def convert_beamerblocks(document): document.warning("Wrong parent layout!") i += 1 continue - j = parent[2] parbeg = parent[3] + parend = parent[2] + j = parend if i != -1: + # If the paragraph starts with a language switch, adjust parbeg + if len(document.body[parbeg]) == 0 and parbeg < parend \ + and document.body[parbeg + 1].startswith("\\lang"): + parbeg += 2 if document.body[parbeg] == "\\begin_inset ERT": - ertcont = parbeg + 5 + ertcontfirstline = parbeg + 5 + lastertbeg = -1 + lastertend = -1 + while True: + # Find the last ERT in this paragraph used for arguments + # (which might also be the first) + lastertbeg = find_token_backwards(document.body, "\\begin_inset ERT", j) + if lastertbeg == -1: + document.warning("Last ERT not found!") + break + lastertend = find_end_of_inset(document.body, lastertbeg) + if lastertend == -1: + document.warning("End of last ERT not found!") + break + # Is this ERT really used for an argument? + # Note: This will fail when non-argument ERTs actually use brackets + # (e.g. \pause{}) + regexp = re.compile(r'.*[>\]\}]', re.IGNORECASE) + cbracket = find_re(document.body, regexp, lastertbeg, lastertend) + if cbracket != -1: + break + if lastertbeg == parbeg: + break + j = lastertbeg - 1 + if lastertbeg == -1 or lastertend == -1: + break + ertcontlastline = lastertend - 3 while True: - if document.body[ertcont].startswith("<"): + if document.body[ertcontfirstline].lstrip().startswith("<"): # This is an overlay specification # strip off the < - document.body[ertcont] = document.body[ertcont][1:] - if document.body[ertcont].endswith(">"): + document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:] + if document.body[ertcontlastline].rstrip().endswith(">"): # strip off the > - document.body[ertcont] = document.body[ertcont][:-1] + document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1] # Convert to ArgInset document.body[parbeg] = "\\begin_inset Argument 1" - elif document.body[ertcont].endswith("}"): + elif document.body[ertcontlastline].rstrip().endswith("}"): + # strip off the } + document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1] # divide the args - tok = document.body[ertcont].find('>{') + ertcontdivline = ertcontfirstline + tok = document.body[ertcontdivline].find('>{') + if tok == -1: + regexp = re.compile(r'.*>\{', re.IGNORECASE) + ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend) + tok = document.body[ertcontdivline].find('>{') if tok != -1: - document.body[ertcont : ertcont + 1] = [document.body[ertcont][:tok], + if ertcontfirstline < ertcontlastline: + # Multiline ERT. Might contain TeX code. Embrace in ERT. + document.body[ertcontlastline : ertcontlastline + 1] = [ + document.body[ertcontlastline], '\\end_layout', '', '\\end_inset'] + if ertcontdivline == ertcontfirstline: + document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok], + '\\end_layout', '', '\\end_inset', '', + '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2', + 'status collapsed', '', '\\begin_layout Plain Layout', + '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout', + document.body[ertcontdivline][tok + 2:]] + else: + document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok], + '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2', + 'status collapsed', '', '\\begin_layout Plain Layout', + '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout', + document.body[ertcontdivline][tok + 2:]] + else: + document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok], '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2', 'status collapsed', '', '\\begin_layout Plain Layout', - document.body[ertcont][tok + 2:-1]] - # Convert to ArgInset - document.body[parbeg] = "\\begin_inset Argument 1" - elif document.body[ertcont].startswith("{"): + document.body[ertcontdivline][tok + 2:]] + else: + # check if have delimiters in two different ERTs + tok = document.body[ertcontdivline].find('>') + if tok == -1: + regexp = re.compile(r'.*>', re.IGNORECASE) + ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend) + tok = document.body[ertcontdivline].find('>') + if tok != -1: + tokk = document.body[ertcontdivline].find('{') + if tokk == -1: + regexp = re.compile(r'.*\{', re.IGNORECASE) + ertcontdivlinetwo = find_re(document.body, regexp, ertcontfirstline, lastertend) + tokk = document.body[ertcontdivlinetwo].find('{') + if tokk != -1: + if ertcontfirstline < ertcontlastline: + # Multiline ERT. Might contain TeX code. Embrace in ERT. + document.body[ertcontlastline : ertcontlastline + 1] = [ + document.body[ertcontlastline], '\\end_layout', '', '\\end_inset'] + document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok], + '\\end_layout', '', '\\end_inset', '', '\\end_layout', '', + '\\end_inset', '', '', '\\begin_inset Argument 2', + 'status collapsed', '', '\\begin_layout Plain Layout', + '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout', + document.body[ertcontdivlinetwo][tokk + 1:]] + else: + document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok], + '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 2', + 'status collapsed', '', '\\begin_layout Plain Layout', + document.body[ertcontdivlinetwo][tokk + 1:]] + # Convert to ArgInset + if ertcontfirstline < ertcontlastline: + # Multiline ERT. Might contain TeX code. Embrace in ERT. + document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 1', + 'status collapsed', '', '\\begin_layout Plain Layout', + '\\begin_inset ERT', ''] + else: + document.body[parbeg] = "\\begin_inset Argument 1" + elif document.body[ertcontfirstline].lstrip().startswith("{"): # This is the block title - if document.body[ertcont].endswith("}"): + if document.body[ertcontlastline].rstrip().endswith("}"): # strip off the braces - document.body[ertcont] = document.body[ertcont][1:-1] + document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:] + document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1] + if ertcontfirstline < ertcontlastline: + # Multiline ERT. Might contain TeX code. Embrace in ERT. + document.body[parend : parend + 1] = [ + document.body[parend], '\\end_inset', '', '\\end_layout'] + document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 2', + 'status collapsed', '', '\\begin_layout Plain Layout', + '\\begin_inset ERT', ''] + else: + # Convert to ArgInset + document.body[parbeg] = "\\begin_inset Argument 2" + # the overlay argument can also follow the title, so ... + elif document.body[ertcontlastline].rstrip().endswith(">"): + # strip off the { + document.body[ertcontfirstline] = document.body[ertcontfirstline].lstrip()[1:] + # strip off the > + document.body[ertcontlastline] = document.body[ertcontlastline].rstrip()[:-1] + # divide the args + ertcontdivline = ertcontfirstline + tok = document.body[ertcontdivline].find('}<') + if tok == -1: + regexp = re.compile(r'.*\}<', re.IGNORECASE) + ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend) + tok = document.body[ertcontdivline].find('}<') + if tok != -1: + if ertcontfirstline < ertcontlastline: + # Multiline ERT. Might contain TeX code. Embrace in ERT. + document.body[ertcontlastline : ertcontlastline + 1] = [ + document.body[ertcontlastline], '\\end_layout', '', '\\end_inset'] + if ertcontdivline == ertcontfirstline: + document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok], + '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1', + 'status collapsed', '', '\\begin_layout Plain Layout', + '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout', + document.body[ertcontdivline][tok + 2:]] + else: + document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok], + '\\end_layout', '', '\\end_inset', '', + '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1', + 'status collapsed', '', '\\begin_layout Plain Layout', + '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout', + document.body[ertcontdivline][tok + 2:]] + else: + document.body[ertcontdivline : ertcontdivline + 1] = [document.body[ertcontdivline][:tok], + '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1', + 'status collapsed', '', '\\begin_layout Plain Layout', + document.body[ertcontdivline][tok + 2:]] + else: + # check if have delimiters in two different ERTs + tok = document.body[ertcontdivline].find('}') + if tok == -1: + regexp = re.compile(r'.*\}', re.IGNORECASE) + ertcontdivline = find_re(document.body, regexp, ertcontfirstline, lastertend) + tok = document.body[ertcontdivline].find('}') + if tok != -1: + tokk = document.body[ertcontdivline].find('<') + if tokk == -1: + regexp = re.compile(r'.*<', re.IGNORECASE) + ertcontdivlinetwo = find_re(document.body, regexp, ertcontfirstline, lastertend) + tokk = document.body[ertcontdivlinetwo].find('<') + if tokk != -1: + if ertcontfirstline < ertcontlastline: + # Multiline ERT. Might contain TeX code. Embrace in ERT. + document.body[ertcontlastline : ertcontlastline + 1] = [ + document.body[ertcontlastline], '\\end_layout', '', '\\end_inset'] + document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok], + '\\end_layout', '', '\\end_inset', '', '\\end_layout', '', + '\\end_inset', '', '', '\\begin_inset Argument 1', + 'status collapsed', '', '\\begin_layout Plain Layout', + '\\begin_inset ERT', '', 'status open' '', '\\begin_layout Plain Layout', + document.body[ertcontdivlinetwo][tokk + 1:]] + else: + document.body[ertcontdivline : ertcontdivlinetwo + 1] = [document.body[ertcontdivline][:tok], + '\\end_layout', '', '\\end_inset', '', '', '\\begin_inset Argument 1', + 'status collapsed', '', '\\begin_layout Plain Layout', + document.body[ertcontdivlinetwo][tokk + 1:]] # Convert to ArgInset - document.body[parbeg] = "\\begin_inset Argument 2" - elif count_pars_in_inset(document.body, ertcont) > 1: + if ertcontfirstline < ertcontlastline: + # Multiline ERT. Might contain TeX code. Embrace in ERT. + document.body[parbeg : parbeg + 1] = ['\\begin_inset Argument 2', + 'status collapsed', '', '\\begin_layout Plain Layout', + '\\begin_inset ERT', ''] + else: + document.body[parbeg] = "\\begin_inset Argument 2" + elif count_pars_in_inset(document.body, ertcontfirstline) > 1: # Multipar ERT. Skip this. break else: - convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, False) + # ERT has contents after the closing bracket. We cannot convert this. + # convert_TeX_brace_to_Argument cannot either. + #convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, False) + break else: break j = find_end_of_layout(document.body, i) @@ -2954,7 +3306,7 @@ def convert_beamerblocks(document): m = find_token(document.body, "\\begin_inset ERT", l, j) if m == -1: break - ertcont = m + 5 + ertcontfirstline = m + 5 parbeg = m i = j @@ -3033,12 +3385,12 @@ def revert_overprint(document): continue endseq = j subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{overprint}") - esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") + esubst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\end{overprint}") endseq = endseq + len(esubst) - len(document.body[j : j]) if document.body[j] == "\\end_deeper": - document.body[j : j] = ["\\end_deeper", ""] + esubst + document.body[j : j] = [""] + esubst + ["", "\\end_layout"] else: - document.body[j : j] = esubst + document.body[j : j] = ["\\end_layout", ""] + esubst r = i while r < j: if document.body[r] == "\\begin_deeper": @@ -3051,19 +3403,22 @@ def revert_overprint(document): r = r + 1 argbeg = find_token(document.body, "\\begin_inset Argument 1", i, j) if argbeg != -1: - argend = find_end_of_inset(document.body, argbeg) - if argend == -1: - document.warning("Malformed LyX document. Cannot find end of Overprint argument!") - i += 1 - continue - beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg) - endPlain = find_end_of_layout(document.body, beginPlain) - content = document.body[beginPlain + 1 : endPlain] - # Adjust range end - endseq = endseq - len(document.body[argbeg : argend]) - # Remove arg inset - del document.body[argbeg : argend + 1] - subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]") + # Is this really our argument? + nested = find_token(document.body, "\\begin_deeper", i, argbeg) + if nested != -1: + argend = find_end_of_inset(document.body, argbeg) + if argend == -1: + document.warning("Malformed LyX document. Cannot find end of Overprint argument!") + i += 1 + continue + beginPlain = find_token(document.body, "\\begin_layout Plain Layout", argbeg) + endPlain = find_end_of_layout(document.body, beginPlain) + content = document.body[beginPlain + 1 : endPlain] + # Adjust range end + endseq = endseq - len(document.body[argbeg : argend]) + # Remove arg inset + del document.body[argbeg : argend + 1] + subst += put_cmd_in_ert("[") + content + put_cmd_in_ert("]") endseq = endseq - len(document.body[i : i]) document.body[i : i] = subst + ["\\end_layout"] @@ -3275,7 +3630,7 @@ def convert_captionlayouts(document): if i == -1: return val = get_value(document.body, "\\begin_layout", i) - if val in caption_dict.keys(): + if val in list(caption_dict.keys()): j = find_end_of_layout(document.body, i) if j == -1: document.warning("Malformed LyX document: Missing `\\end_layout'.") @@ -3311,7 +3666,7 @@ def revert_captionlayouts(document): val = "" if m: val = m.group(1) - if val not in caption_dict.keys(): + if val not in list(caption_dict.keys()): i += 1 continue @@ -3400,10 +3755,10 @@ def revert_fragileframe(document): continue endseq = j subst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\begin{frame}") - esubst = ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\end{frame}") + esubst = ["\\begin_layout Standard"] + put_cmd_in_ert("\\end{frame}") endseq = endseq + len(esubst) - len(document.body[j : j]) if document.body[j] == "\\end_deeper": - document.body[j : j] = ["\\end_deeper", ""] + esubst + document.body[j : j] = [""] + esubst + ["", "\\end_layout"] else: document.body[j : j] = esubst for q in range(i, j): @@ -3492,7 +3847,7 @@ def revert_newframes(document): val = "" if m: val = m.group(1) - if val not in frame_dict.keys(): + if val not in list(frame_dict.keys()): i += 1 continue # Find end of sequence @@ -3503,12 +3858,12 @@ def revert_newframes(document): continue endseq = j subst = ["\\begin_layout %s" % frame_dict[val]] - esubst = ["\\end_layout", "", "\\begin_layout EndFrame", "", "\\end_layout"] + esubst = ["", "\\begin_layout EndFrame", "", "\\end_layout"] endseq = endseq + len(esubst) - len(document.body[j : j]) if document.body[j] == "\\end_deeper": - document.body[j : j] = ["\\end_deeper", ""] + esubst - else: document.body[j : j] = esubst + else: + document.body[j+1 : j+1] = esubst for q in range(i, j): if document.body[q] == "\\begin_layout %s" % val: document.body[q] = "\\begin_layout %s" % document.default_layout @@ -3608,7 +3963,7 @@ def convert_encodings(document): if i == -1: return val = get_value(document.header, "\\inputencoding", i) - if val in LaTeX2LyX_enc_dict.keys(): + if val in list(LaTeX2LyX_enc_dict.keys()): document.header[i] = "\\inputencoding %s" % LaTeX2LyX_enc_dict[val] elif val not in known_enc_tuple: document.warning("Ignoring unknown input encoding: `%s'" % val) @@ -3649,7 +4004,7 @@ def revert_encodings(document): if i == -1: return val = get_value(document.header, "\\inputencoding", i) - if val in LyX2LaTeX_enc_dict.keys(): + if val in list(LyX2LaTeX_enc_dict.keys()): document.header[i] = "\\inputencoding %s" % LyX2LaTeX_enc_dict[val] elif val not in known_enc_tuple: document.warning("Ignoring unknown input encoding: `%s'" % val) @@ -3817,6 +4172,7 @@ def convert_lyxframes(document): # Step III: find real frame end j = j + 8 jj = j + inInset = get_containing_inset(document.body, i) while True: fend = find_token(document.body, "\\begin_layout", jj) if fend == -1: @@ -3826,7 +4182,11 @@ def convert_lyxframes(document): if val not in frameend: jj = fend + 1 continue - old = document.body[fend] + # is this frame nested in an inset (e.g., Note)? + if inInset != False: + # if so, end the frame inside the inset + if inInset[2] < fend: + fend = inInset[2] if val == frametype: document.body[fend : fend] = ['\\end_deeper', '', '\\begin_layout Separator', '', '\\end_layout'] # consider explicit EndFrames between two identical frame types @@ -4079,7 +4439,7 @@ def revert_mbox_fbox(document): i += 1 continue BeginLayout = find_token(document.body, "\\begin_layout Plain Layout", j) - EndLayout = find_token(document.body, "\\end_layout", BeginLayout) + EndLayout = find_end_of_layout(document.body, BeginLayout) # replace if width is "" if (width == '""'): document.body[EndLayout:k + 1] = put_cmd_in_ert("}") @@ -4190,80 +4550,124 @@ def revert_tibetan(document): # ############# -# the idea here is that we will have a sequence of chunk paragraphs -# we want to convert them to paragraphs in a chunk inset -# the last will be discarded -# the first should look like: <>= -# will will discard the delimiters, and put the contents into the -# optional argument of the inset +# The idea here is that we will have a sequence of chunk paragraphs. +# We want to convert them to paragraphs in one or several chunk insets. +# Individual chunks are terminated by the character @ on the last line. +# This line will be discarded, and following lines are treated as new +# chunks, which go into their own insets. +# The first line of a chunk should look like: <>= +# We will discard the delimiters, and put the CONTENT into the +# optional argument of the inset, if the CONTENT is non-empty. def convert_chunks(document): - first_re = re.compile(r'<<(.*)>>=') - k = 0 + first_re = re.compile(r'<<(.*)>>=(.*)') + file_pos = 0 while True: - # the beginning of this sequence - i = k # find start of a block of chunks - i = find_token(document.body, "\\begin_layout Chunk", i) + i = find_token(document.body, "\\begin_layout Chunk", file_pos) if i == -1: return start = i end = -1 contents = [] + chunk_started = False while True: # process the one we just found j = find_end_of_layout(document.body, i) if j == -1: document.warning("Malformed LyX documents. Can't find end of Chunk layout!") - break - thischunk = "".join(document.body[i + 1:j]) - contents.append(document.body[i + 1:j]) + # there is no point continuing, as we will run into the same error again. + return + this_chunk = "".join(document.body[i + 1:j]) - if thischunk == "@": + # there may be empty lines between chunks + # we just skip them. + if not chunk_started: + if this_chunk != "": + # new chunk starts + chunk_started = True + + if chunk_started: + contents.append(document.body[i + 1:j]) + + # look for potential chunk terminator + # on the last line of the chunk paragraph + if document.body[j - 1] == "@": break - # look for the next one - i = j - i = find_token(document.body, "\\begin_layout", i) + # look for subsequent chunk paragraph + i = find_token(document.body, "\\begin_layout", j) if i == -1: break - layout = get_value(document.body, "\\begin_layout", i) - #sys.stderr.write(layout+ '\n') - if layout != "Chunk": + if get_value(document.body, "\\begin_layout", i) != "Chunk": break - if j == -1: - # error, but we can try to continue - k = j + 1 - continue - - end = j + 1 - k = end - - # the last chunk should simply have an "@" in it - - if ''.join(contents[-1]) != "@": - document.warning("Unexpected chunk contents.") + file_pos = end = j + 1 + + # The last chunk should simply have an "@" in it + # or at least end with "@" (can happen if @ is + # preceded by a newline) + lastpar = '' + if len(contents) > 0: + lastpar = ''.join(contents[-1]) + if not lastpar.endswith("@"): + document.warning("Unexpected chunk content: chunk not terminated by '@'!") + if len(contents) == 0: + # convert empty chunk layouts to Standard + document.body[start] = "\\begin_layout Standard" continue - contents.pop() + if lastpar == "@": + # chunk par only contains "@". Just drop it. + contents.pop() + else: + # chunk par contains more. Only drop the "@". + contents[-1].pop() - # the first item should look like: <>= - # we want the inside + # The first line should look like: <>= + # We want the CONTENT optarg = ' '.join(contents[0]) optarg.strip() + # We can already have real chunk content in + # the first par (separated from the options by a newline). + # We collect such stuff to re-insert it later. + postoptstuff = [] + match = first_re.search(optarg) if match: optarg = match.groups()[0] + if match.groups()[1] != "": + postopt = False + for c in contents[0]: + if c.endswith(">>="): + postopt = True + continue + if postopt: + postoptstuff.append(c) + # We have stripped everything. This can be deleted. contents.pop(0) - newstuff = ['\\begin_layout Standard', - '\\begin_inset Flex Chunk', - 'status open', '', - '\\begin_layout Plain Layout', ''] + newstuff = ['\\begin_layout Standard'] - if match: + # Maintain paragraph parameters + par_params = ["\\noindent", "\\indent", "\\indent-toggle", "\\leftindent", + "\\start_of_appendix", "\\paragraph_spacing", "\\align", + "\\labelwidthstring"] + parms = start + 1 + while True: + if document.body[parms].split(' ', 1)[0] not in par_params: + break + newstuff.extend([document.body[parms]]) + parms += 1 + + newstuff.extend( + ['\\begin_inset Flex Chunk', + 'status open', '', + '\\begin_layout Plain Layout', '']) + + # If we have a non-empty optional argument, insert it. + if match and optarg != "": newstuff.extend( ['\\begin_inset Argument 1', 'status open', '', @@ -4272,12 +4676,34 @@ def convert_chunks(document): '\\end_layout', '', '\\end_inset', '']) - didone = False + # Since we already opened a Plain layout, the first paragraph + # does not need to do that. + did_one_par = False + if postoptstuff: + # we need to replace newlines with new layouts + start_newline = -1 + started_text = False + for lno in range(0,len(postoptstuff)): + if postoptstuff[lno].startswith("\\begin_inset Newline newline"): + start_newline = lno + elif start_newline != -1: + if postoptstuff[lno].startswith("\\end_inset"): + # replace that bit, but only if we already have some text + # and we're not at the end except for a blank line + if started_text and \ + (lno != len(postoptstuff) - 2 or postoptstuff[-1] != ""): + newstuff.extend(['\\end_layout', '\n', '\\begin_layout Plain Layout', '\n']) + start_newline = -1 + started_text = True + else: + newstuff.extend([postoptstuff[lno]]) + newstuff.append('\\end_layout') + did_one_par = True for c in contents: - if didone: + if did_one_par: newstuff.extend(['', '\\begin_layout Plain Layout', '']) else: - didone = True + did_one_par = True newstuff.extend(c) newstuff.append('\\end_layout') @@ -4285,7 +4711,7 @@ def convert_chunks(document): document.body[start:end] = newstuff - k += len(newstuff) - (end - start) + file_pos += len(newstuff) - (end - start) def revert_chunks(document): @@ -4302,7 +4728,7 @@ def revert_chunks(document): continue # Look for optional argument - have_optarg = False + optarg = "" ostart = find_token(document.body, "\\begin_inset Argument 1", i, iend) if ostart != -1: oend = find_end_of_inset(document.body, ostart) @@ -4312,7 +4738,6 @@ def revert_chunks(document): else: m = find_end_of_layout(document.body, k) optarg = "".join(document.body[k+1:m]) - have_optarg = True # We now remove the optional argument, so we have something # uniform on which to work @@ -4341,8 +4766,7 @@ def revert_chunks(document): k = j # we now need to wrap all of these paragraphs in chunks newlines = [] - if have_optarg: - newlines.extend(["\\begin_layout Chunk", "", "<<" + optarg + ">>=", "\\end_layout", ""]) + newlines.extend(["\\begin_layout Chunk", "", "<<" + optarg + ">>=", "\\end_layout", ""]) for stuff in parlist: newlines.extend(["\\begin_layout Chunk"] + stuff + ["\\end_layout", ""]) newlines.extend(["\\begin_layout Chunk", "", "@", "\\end_layout", ""]) @@ -4361,13 +4785,16 @@ convert = [ [415, [convert_undertilde]], [416, []], [417, [convert_japanese_encodings]], - [418, []], + [418, [convert_justification]], [419, []], [420, [convert_biblio_style]], [421, [convert_longtable_captions]], [422, [convert_use_packages]], [423, [convert_use_mathtools]], [424, [convert_cite_engine_type]], + # No convert_cancel, since cancel will be loaded automatically + # in format 425 without any possibility to switch it off. + # This has been fixed in format 464. [425, []], [426, []], [427, []], @@ -4417,7 +4844,7 @@ convert = [ [471, [convert_cite_engine_type_default]], [472, []], [473, []], - [474, [convert_chunks]], + [474, [convert_chunks, cleanup_beamerargs]], ] revert = [