]> git.lyx.org Git - features.git/blobdiff - lib/lyx2lyx/lyx_2_4.py
lyx2lyx: fix index reversion
[features.git] / lib / lyx2lyx / lyx_2_4.py
index 6283631d26effaf51ff2ee0b1c0132015f4329aa..43b7ce31248d6478aa1a8489a0aca853edd9c679 100644 (file)
@@ -26,14 +26,14 @@ from datetime import (datetime, date, time)
 
 # Uncomment only what you need to import, please.
 
-from parser_tools import (count_pars_in_inset, del_token, find_end_of_inset,
-    find_end_of_layout, find_token, find_token_backwards, find_token_exact,
-    find_re, get_bool_value,
-    get_containing_layout, get_option_value, get_value, get_quoted_value)
-#    del_value, del_complete_lines,
-#    find_complete_lines, find_end_of,
+from parser_tools import (count_pars_in_inset, del_complete_lines, del_token,
+     find_end_of, find_end_of_inset, find_end_of_layout, find_token,
+     find_token_backwards, find_token_exact, find_re, get_bool_value,
+     get_containing_inset, get_containing_layout, get_option_value, get_value,
+     get_quoted_value)
+#    del_value, 
+#    find_complete_lines,
 #    find_re, find_substring,
-#    get_containing_inset,
 #    is_in_inset, set_bool_value
 #    find_tokens, check_token
 
@@ -752,7 +752,7 @@ def revert_floatalignment(document):
         i += 1
 
 def revert_tuftecite(document):
-    """Revert \cite commands in tufte classes"""
+    r"""Revert \cite commands in tufte classes"""
 
     tufte = ["tufte-book", "tufte-handout"]
     if document.textclass not in tufte:
@@ -1223,7 +1223,7 @@ def revert_dateinfo(document):
             if len(datecomps) > 1:
                 argv = datecomps[0]
                 isodate = datecomps[1]
-                m = re.search('(\d\d\d\d)-(\d\d)-(\d\d)', isodate)
+                m = re.search(r'(\d\d\d\d)-(\d\d)-(\d\d)', isodate)
                 if m:
                     dte = date(int(m.group(1)), int(m.group(2)), int(m.group(3)))
 # FIXME if we had the path to the original document (not the one in the tmp dir),
@@ -1403,11 +1403,11 @@ def revert_timeinfo(document):
             if len(timecomps) > 1:
                 argv = timecomps[0]
                 isotime = timecomps[1]
-                m = re.search('(\d\d):(\d\d):(\d\d)', isotime)
+                m = re.search(r'(\d\d):(\d\d):(\d\d)', isotime)
                 if m:
                     tme = time(int(m.group(1)), int(m.group(2)), int(m.group(3)))
                 else:
-                    m = re.search('(\d\d):(\d\d)', isotime)
+                    m = re.search(r'(\d\d):(\d\d)', isotime)
                     if m:
                         tme = time(int(m.group(1)), int(m.group(2)))
 # FIXME if we had the path to the original document (not the one in the tmp dir),
@@ -1875,7 +1875,7 @@ def revert_new_languages(document):
                      "korean":         ("", "korean"),
                     }
     if document.language in new_languages:
-        used_languages = set((document.language, ))
+        used_languages = {document.language}
     else:
         used_languages = set()
     i = 0
@@ -3475,6 +3475,15 @@ def revert_memoir_endnotes(document):
 def revert_totalheight(document):
     " Reverts graphics height parameter from totalheight to height "
 
+    relative_heights = {
+        "\\textwidth" : "text%",
+        "\\columnwidth" : "col%",
+        "\\paperwidth" : "page%",
+        "\\linewidth" : "line%",
+        "\\textheight" : "theight%",
+        "\\paperheight" : "pheight%",
+        "\\baselineskip " : "baselineskip%"
+    }
     i = 0
     while (True):
         i = find_token(document.body, "\\begin_inset Graphics", i)
@@ -3487,6 +3496,7 @@ def revert_totalheight(document):
             continue
 
         rx = re.compile(r'\s*special\s*(\S+)$')
+        rxx = re.compile(r'(\d*\.*\d+)(\S+)$')
         k = find_re(document.body, rx, i, j)
         special = ""
         oldheight = ""
@@ -3496,8 +3506,15 @@ def revert_totalheight(document):
                 special = m.group(1)
             mspecial = special.split(',')
             for spc in mspecial:
-                if spc[:7] == "height=":
+                if spc.startswith("height="):
                     oldheight = spc.split('=')[1]
+                    ms = rxx.search(oldheight)
+                    if ms:
+                        oldunit = ms.group(2)
+                        if oldunit in list(relative_heights.keys()):
+                            oldval = str(float(ms.group(1)) * 100)
+                            oldunit = relative_heights[oldunit]
+                            oldheight = oldval + oldunit
                     mspecial.remove(spc)
                     break
             if len(mspecial) > 0:
@@ -3534,6 +3551,15 @@ def revert_totalheight(document):
 def convert_totalheight(document):
     " Converts graphics height parameter from totalheight to height "
 
+    relative_heights = {
+        "text%" : "\\textwidth",
+        "col%"  : "\\columnwidth",
+        "page%" : "\\paperwidth",
+        "line%" : "\\linewidth",
+        "theight%" : "\\textheight",
+        "pheight%" : "\\paperheight",
+        "baselineskip%" : "\\baselineskip"
+    }
     i = 0
     while (True):
         i = find_token(document.body, "\\begin_inset Graphics", i)
@@ -3564,19 +3590,23 @@ def convert_totalheight(document):
             else:
                 special = ""
 
-        rx = re.compile(r'(\s*height\s*)(\S+)$')
+        rx = re.compile(r'(\s*height\s*)(\d+)(\S+)$')
         kk = find_re(document.body, rx, i, j)
         if kk != -1:
             m = rx.match(document.body[kk])
             val = ""
             if m:
                 val = m.group(2)
+                unit = m.group(3)
+                if unit in list(relative_heights.keys()):
+                    val = str(float(val) / 100)
+                    unit = relative_heights[unit]
                 if k != -1:
                     if special != "":
-                        val = val + "," + special
+                        val = val + unit + "," + special
                     document.body[k] = "\tspecial " + "height=" + val
                 else:
-                    document.body.insert(kk + 1, "\tspecial height=" + val)
+                    document.body.insert(kk + 1, "\tspecial height=" + val + unit)
                 if newheight != "":
                     document.body[kk] = m.group(1) + newheight
                 else:
@@ -3744,7 +3774,7 @@ def revert_counter_inset(document):
             ert = put_cmd_in_ert("\\setcounter{%s}{\\value{%s}}" % (cnt, savecnt))
         else:
             document.warning("Unknown counter command `%s' in inset at line %d!" % (cnt, i))
-            
+
         if ert:
             document.body[i : j + 1] = ert
         i += 1
@@ -3771,7 +3801,7 @@ def revert_ams_spaces(document):
         subst = put_cmd_in_ert(inset)
         document.body[i : end + 1] = subst
         Found = True
-      
+
     if Found == True:
         # load amsmath in the preamble if not already loaded
         i = find_token(document.header, "\\use_package amsmath 2", 0)
@@ -3782,18 +3812,18 @@ def revert_ams_spaces(document):
 
 def convert_parskip(document):
     " Move old parskip settings to preamble "
-    
+
     i = find_token(document.header, "\\paragraph_separation skip", 0)
     if i == -1:
         return
-    
+
     j = find_token(document.header, "\\defskip", 0)
     if j == -1:
         document.warning("Malformed LyX document! Missing \\defskip.")
         return
-    
+
     val = get_value(document.header, "\\defskip", j)
-    
+
     skipval = "\\medskipamount"
     if val == "smallskip" or val == "medskip" or val == "bigskip":
         skipval = "\\" + val + "amount"
@@ -3801,25 +3831,25 @@ def convert_parskip(document):
         skipval = val
 
     add_to_preamble(document, ["\\setlength{\\parskip}{" + skipval + "}", "\\setlength{\\parindent}{0pt}"])
-    
+
     document.header[i] = "\\paragraph_separation indent"
     document.header[j] = "\\paragraph_indentation default"
 
 
 def revert_parskip(document):
     " Revert new parskip settings to preamble "
-    
+
     i = find_token(document.header, "\\paragraph_separation skip", 0)
     if i == -1:
         return
-    
+
     j = find_token(document.header, "\\defskip", 0)
     if j == -1:
         document.warning("Malformed LyX document! Missing \\defskip.")
         return
-    
+
     val = get_value(document.header, "\\defskip", j)
-    
+
     skipval = ""
     if val == "smallskip" or val == "medskip" or val == "bigskip":
         skipval = "[skip=\\" + val + "amount]"
@@ -3827,9 +3857,9 @@ def revert_parskip(document):
         skipval = "[skip=\\baselineskip]"
     elif val != "halfline":
         skipval = "[skip={" + val + "}]"
-    
+
     add_to_preamble(document, ["\\usepackage" + skipval + "{parskip}"])
-    
+
     document.header[i] = "\\paragraph_separation indent"
     document.header[j] = "\\paragraph_indentation default"
 
@@ -3922,20 +3952,601 @@ def revert_libertinus_sftt_fonts(document):
                     add_to_preamble(document, ["\\renewcommand*{\\LibertinusMono@scale}{" + str(tt_scale / 100.0) + "}"])
 
 
-def convert_docbook_table_output(document):
-    if find_token(document.header, '\\docbook_table_output') != -1:
-        document.warning("Malformed LyX file: \\docbook_table_output found before format 598!")
-    else:
-        document.header.append('\\docbook_table_output 0')
+def revert_docbook_table_output(document):
+    i = find_token(document.header, '\\docbook_table_output')
+    if i != -1:
+        del document.header[i]
 
 
-def revert_docbook_table_output(document):
-    i = find_token(document.header, '\\docbook_table_output 0')
-    i = find_token(document.header, '\\docbook_table_output 1') if i == -1 else i
+def revert_nopagebreak(document):
+    while True:
+        i = find_token(document.body, "\\begin_inset Newpage nopagebreak")
+        if i == -1:
+            return
+        end = find_end_of_inset(document.body, i)
+        if end == 1:
+            document.warning("Malformed LyX document: Could not find end of Newpage inset.")
+            continue
+        subst = put_cmd_in_ert("\\nopagebreak{}")
+        document.body[i : end + 1] = subst
+
+
+def revert_hrquotes(document):
+    " Revert Hungarian Quotation marks "
+    
+    i = find_token(document.header, "\\quotes_style hungarian", 0)
     if i != -1:
+        document.header[i] = "\\quotes_style polish"
+
+    i = 0
+    while True:
+        i = find_token(document.body, "\\begin_inset Quotes h")
+        if i == -1:
+            return
+        if document.body[i] == "\\begin_inset Quotes hld":
+            document.body[i] = "\\begin_inset Quotes pld"
+        elif document.body[i] == "\\begin_inset Quotes hrd":
+            document.body[i] = "\\begin_inset Quotes prd"
+        elif document.body[i] == "\\begin_inset Quotes hls":
+            document.body[i] = "\\begin_inset Quotes ald"
+        elif document.body[i] == "\\begin_inset Quotes hrs":
+            document.body[i] = "\\begin_inset Quotes ard"
+
+
+def convert_math_refs(document):
+    i = 0
+    while True:
+        i = find_token(document.body, "\\begin_inset Formula", i)
+        if i == -1:
+            break
+        j = find_end_of_inset(document.body, i)
+        if j == -1:
+            document.warning("Can't find end of inset at line %d of body!" % i)
+            i += 1
+            continue
+        while i < j:
+            document.body[i] = document.body[i].replace("\\prettyref", "\\formatted")
+            i += 1
+        
+
+def revert_math_refs(document):
+    i = 0
+    while True:
+        i = find_token(document.body, "\\begin_inset Formula", i)
+        if i == -1:
+            break
+        j = find_end_of_inset(document.body, i)
+        if j == -1:
+            document.warning("Can't find end of inset at line %d of body!" % i)
+            i += 1
+            continue
+        while i < j:
+            document.body[i] = document.body[i].replace("\\formatted", "\\prettyref")
+            if "\\labelonly" in document.body[i]:
+                document.body[i] = re.sub("\\\\labelonly{([^}]+?)}", "\\1", document.body[i])
+            i += 1
+
+
+def convert_branch_colors(document):
+    " Convert branch colors to semantic values "
+
+    i = 0
+    while True:
+        i = find_token(document.header, "\\branch", i)
+        if i == -1:
+            break
+        j = find_token(document.header, "\\end_branch", i)
+        if j == -1:
+           document.warning("Malformed LyX document. Can't find end of branch definition!")
+           break
+        # We only support the standard LyX background for now
+        k = find_token(document.header, "\\color #faf0e6", i, j)
+        if k != -1:
+           document.header[k] = "\\color background"
+        i += 1
+
+
+def revert_branch_colors(document):
+    " Revert semantic branch colors "
+
+    i = 0
+    while True:
+        i = find_token(document.header, "\\branch", i)
+        if i == -1:
+            break
+        j = find_token(document.header, "\\end_branch", i)
+        if j == -1:
+           document.warning("Malformed LyX document. Can't find end of branch definition!")
+           break
+        k = find_token(document.header, "\\color", i, j)
+        if k != -1:
+           bcolor = get_value(document.header, "\\color", k)
+           if bcolor[1] != "#":
+               # this will be read as background by LyX 2.3
+               document.header[k] = "\\color none"
+        i += 1
+
+
+def revert_darkmode_graphics(document):
+    " Revert darkModeSensitive InsetGraphics param "
+
+    i = 0
+    while (True):
+        i = find_token(document.body, "\\begin_inset Graphics", i)
+        if i == -1:
+            break
+        j = find_end_of_inset(document.body, i)
+        if j == -1:
+            document.warning("Can't find end of graphics inset at line %d!!" %(i))
+            i += 1
+            continue
+        k = find_token(document.body, "\tdarkModeSensitive", i, j)
+        if k != -1:
+            del document.body[k]
+        i += 1
+
+
+def revert_branch_darkcols(document):
+    " Revert dark branch colors "
+
+    i = 0
+    while True:
+        i = find_token(document.header, "\\branch", i)
+        if i == -1:
+            break
+        j = find_token(document.header, "\\end_branch", i)
+        if j == -1:
+           document.warning("Malformed LyX document. Can't find end of branch definition!")
+           break
+        k = find_token(document.header, "\\color", i, j)
+        if k != -1:
+            m = re.search('\\\\color (\\S+) (\\S+)', document.header[k])
+            if m:
+                document.header[k] = "\\color " + m.group(1)
+        i += 1
+
+
+def revert_vcolumns2(document):
+    """Revert varwidth columns with line breaks etc."""
+    i = 0
+    needvarwidth = False
+    needarray = False
+    needcellvarwidth = False
+    try:
+        while True:
+            i = find_token(document.body, "\\begin_inset Tabular", i+1)
+            if i == -1:
+                return
+            j = find_end_of_inset(document.body, i)
+            if j == -1:
+                document.warning("Malformed LyX document: Could not find end of tabular.")
+                continue
+
+            # Collect necessary column information
+            m = i + 1
+            nrows = int(document.body[i+1].split('"')[3])
+            ncols = int(document.body[i+1].split('"')[5])
+            col_info = []
+            for k in range(ncols):
+                m = find_token(document.body, "<column", m)
+                width = get_option_value(document.body[m], 'width')
+                varwidth = get_option_value(document.body[m], 'varwidth')
+                alignment = get_option_value(document.body[m], 'alignment')
+                valignment = get_option_value(document.body[m], 'valignment')
+                special = get_option_value(document.body[m], 'special')
+                col_info.append([width, varwidth, alignment, valignment, special, m])
+                m += 1
+
+            # Now parse cells
+            m = i + 1
+            lines = []
+            for row in range(nrows):
+                for col in range(ncols):
+                    m = find_token(document.body, "<cell", m)
+                    multicolumn = get_option_value(document.body[m], 'multicolumn') != ""
+                    multirow = get_option_value(document.body[m], 'multirow') != ""
+                    fixedwidth = get_option_value(document.body[m], 'width') != ""
+                    rotate = get_option_value(document.body[m], 'rotate')
+                    cellalign = get_option_value(document.body[m], 'alignment')
+                    cellvalign = get_option_value(document.body[m], 'valignment')
+                    # Check for: linebreaks, multipars, non-standard environments
+                    begcell = m
+                    endcell = find_token(document.body, "</cell>", begcell)
+                    vcand = False
+                    if find_token(document.body, "\\begin_inset Newline", begcell, endcell) != -1:
+                        vcand = not fixedwidth
+                    elif count_pars_in_inset(document.body, begcell + 2) > 1:
+                        vcand = not fixedwidth
+                    elif get_value(document.body, "\\begin_layout", begcell) != "Plain Layout":
+                        vcand = not fixedwidth
+                    colalignment = col_info[col][2]
+                    colvalignment = col_info[col][3]
+                    if vcand:
+                        if rotate == "" and ((colalignment == "left" and colvalignment == "top") or (multicolumn == True and cellalign == "left" and cellvalign == "top")):
+                            if col_info[col][0] == "" and col_info[col][1] == "" and col_info[col][4] == "":
+                                needvarwidth = True
+                                col_line = col_info[col][5]
+                                needarray = True
+                                vval = "V{\\linewidth}"
+                                if multicolumn:
+                                    document.body[m] = document.body[m][:-1] + " special=\"" + vval + "\">"
+                                else:
+                                    document.body[col_line] = document.body[col_line][:-1] + " special=\"" + vval + "\">"
+                        else:
+                            alarg = ""
+                            if multicolumn or multirow:
+                                if cellvalign == "middle":
+                                    alarg = "[m]"
+                                elif cellvalign == "bottom":
+                                    alarg = "[b]"
+                            else:
+                                if colvalignment == "middle":
+                                    alarg = "[m]"
+                                elif colvalignment == "bottom":
+                                    alarg = "[b]"
+                            flt = find_token(document.body, "\\begin_layout", begcell, endcell)
+                            elt = find_token_backwards(document.body, "\\end_layout", endcell)
+                            if flt != -1 and elt != -1:
+                                extralines = []
+                                # we need to reset character layouts if necessary
+                                el = find_token(document.body, '\\emph on', flt, elt)
+                                if el != -1:
+                                    extralines.append("\\emph default")
+                                el = find_token(document.body, '\\noun on', flt, elt)
+                                if el != -1:
+                                    extralines.append("\\noun default")
+                                el = find_token(document.body, '\\series', flt, elt)
+                                if el != -1:
+                                    extralines.append("\\series default")
+                                el = find_token(document.body, '\\family', flt, elt)
+                                if el != -1:
+                                    extralines.append("\\family default")
+                                el = find_token(document.body, '\\shape', flt, elt)
+                                if el != -1:
+                                    extralines.append("\\shape default")
+                                el = find_token(document.body, '\\color', flt, elt)
+                                if el != -1:
+                                    extralines.append("\\color inherit")
+                                el = find_token(document.body, '\\size', flt, elt)
+                                if el != -1:
+                                    extralines.append("\\size default")
+                                el = find_token(document.body, '\\bar under', flt, elt)
+                                if el != -1:
+                                    extralines.append("\\bar default")
+                                el = find_token(document.body, '\\uuline on', flt, elt)
+                                if el != -1:
+                                    extralines.append("\\uuline default")
+                                el = find_token(document.body, '\\uwave on', flt, elt)
+                                if el != -1:
+                                    extralines.append("\\uwave default")
+                                el = find_token(document.body, '\\strikeout on', flt, elt)
+                                if el != -1:
+                                    extralines.append("\\strikeout default")
+                                document.body[elt:elt+1] = extralines + put_cmd_in_ert("\\end{cellvarwidth}") + [r"\end_layout"]
+                                parlang = -1
+                                for q in range(flt, elt):
+                                    if document.body[q] != "" and document.body[q][0] != "\\":
+                                        break
+                                    if document.body[q][:5] == "\\lang":
+                                        parlang = q
+                                        break
+                                if parlang != -1:
+                                    document.body[parlang+1:parlang+1] = put_cmd_in_ert("\\begin{cellvarwidth}" + alarg)
+                                else:
+                                    document.body[flt+1:flt+1] = put_cmd_in_ert("\\begin{cellvarwidth}" + alarg)
+                                needcellvarwidth = True
+                                needvarwidth = True
+                        # ERT newlines and linebreaks (since LyX < 2.4 automatically inserts parboxes
+                        # with newlines, and we do not want that)
+                        while True:
+                            endcell = find_token(document.body, "</cell>", begcell)
+                            linebreak = False
+                            nl = find_token(document.body, "\\begin_inset Newline newline", begcell, endcell)
+                            if nl == -1:
+                                nl = find_token(document.body, "\\begin_inset Newline linebreak", begcell, endcell)
+                                if nl == -1:
+                                     break
+                                linebreak = True
+                            nle = find_end_of_inset(document.body, nl)
+                            del(document.body[nle:nle+1])
+                            if linebreak:
+                                document.body[nl:nl+1] = put_cmd_in_ert("\\linebreak{}")
+                            else:
+                                document.body[nl:nl+1] = put_cmd_in_ert("\\\\")
+                        # Replace parbreaks in multirow with \\endgraf
+                        if multirow == True:
+                            flt = find_token(document.body, "\\begin_layout", begcell, endcell)
+                            if flt != -1:
+                                while True:
+                                    elt = find_end_of_layout(document.body, flt)
+                                    if elt == -1:
+                                        document.warning("Malformed LyX document! Missing layout end.")
+                                        break
+                                    endcell = find_token(document.body, "</cell>", begcell)
+                                    flt = find_token(document.body, "\\begin_layout", elt, endcell)
+                                    if flt == -1:
+                                        break
+                                    document.body[elt : flt + 1] = put_cmd_in_ert("\\endgraf{}")
+                    m += 1
+
+            i = j
+
+    finally:
+        if needarray == True:
+            add_to_preamble(document, ["\\usepackage{array}"])
+        if needcellvarwidth == True:
+            add_to_preamble(document, ["%% Variable width box for table cells",
+                                       "\\newenvironment{cellvarwidth}[1][t]",
+                                       "    {\\begin{varwidth}[#1]{\\linewidth}}",
+                                       "    {\\@finalstrut\\@arstrutbox\\end{varwidth}}"])
+        if needvarwidth == True:
+            add_to_preamble(document, ["\\usepackage{varwidth}"])
+
+
+def convert_vcolumns2(document):
+    """Convert varwidth ERT to native"""
+    i = 0
+    try:
+        while True:
+            i = find_token(document.body, "\\begin_inset Tabular", i+1)
+            if i == -1:
+                return
+            j = find_end_of_inset(document.body, i)
+            if j == -1:
+                document.warning("Malformed LyX document: Could not find end of tabular.")
+                continue
+
+            # Parse cells
+            nrows = int(document.body[i+1].split('"')[3])
+            ncols = int(document.body[i+1].split('"')[5])
+            m = i + 1
+            lines = []
+            for row in range(nrows):
+                for col in range(ncols):
+                    m = find_token(document.body, "<cell", m)
+                    multirow = get_option_value(document.body[m], 'multirow') != ""
+                    begcell = m
+                    endcell = find_token(document.body, "</cell>", begcell)
+                    vcand = False
+                    cvw = find_token(document.body, "begin{cellvarwidth}", begcell, endcell)
+                    if cvw != -1:
+                        vcand = document.body[cvw - 1] == "\\backslash" and get_containing_inset(document.body, cvw)[0] == "ERT"
+                    if vcand:
+                        # Remove ERTs with cellvarwidth env
+                        ecvw = find_token(document.body, "end{cellvarwidth}", begcell, endcell)
+                        if ecvw != -1:
+                            if document.body[ecvw - 1] == "\\backslash":
+                                eertins = get_containing_inset(document.body, ecvw)
+                                if eertins and eertins[0] == "ERT":
+                                    del document.body[eertins[1] : eertins[2] + 1]
+                             
+                        cvw = find_token(document.body, "begin{cellvarwidth}", begcell, endcell)   
+                        ertins = get_containing_inset(document.body, cvw)
+                        if ertins and ertins[0] == "ERT":
+                            del(document.body[ertins[1] : ertins[2] + 1])
+                        
+                        # Convert ERT newlines (as cellvarwidth detection relies on that)
+                        while True:
+                            endcell = find_token(document.body, "</cell>", begcell)
+                            nl = find_token(document.body, "\\backslash", begcell, endcell)
+                            if nl == -1 or document.body[nl + 2] != "\\backslash":
+                                break
+                            ertins = get_containing_inset(document.body, nl)
+                            if ertins and ertins[0] == "ERT":
+                                document.body[ertins[1] : ertins[2] + 1] = ["\\begin_inset Newline newline", "", "\\end_inset"]
+
+                        # Same for linebreaks
+                        while True:
+                            endcell = find_token(document.body, "</cell>", begcell)
+                            nl = find_token(document.body, "linebreak", begcell, endcell)
+                            if nl == -1 or document.body[nl - 1] != "\\backslash":
+                                break
+                            ertins = get_containing_inset(document.body, nl)
+                            if ertins and ertins[0] == "ERT":
+                                document.body[ertins[1] : ertins[2] + 1] = ["\\begin_inset Newline linebreak", "", "\\end_inset"]
+
+                        # And \\endgraf
+                        if multirow == True:
+                            endcell = find_token(document.body, "</cell>", begcell)
+                            nl = find_token(document.body, "endgraf{}", begcell, endcell)
+                            if nl == -1 or document.body[nl - 1] != "\\backslash":
+                                break
+                            ertins = get_containing_inset(document.body, nl)
+                            if ertins and ertins[0] == "ERT":
+                                    document.body[ertins[1] : ertins[2] + 1] = ["\\end_layout", "", "\\begin_layout Plain Layout"]
+                    m += 1
+
+            i += 1
+
+    finally:
+        del_complete_lines(document.preamble,
+                                ['% Added by lyx2lyx',
+                                 '%% Variable width box for table cells',
+                                 r'\newenvironment{cellvarwidth}[1][t]',
+                                 r'    {\begin{varwidth}[#1]{\linewidth}}',
+                                 r'    {\@finalstrut\@arstrutbox\end{varwidth}}'])
+        del_complete_lines(document.preamble,
+                                ['% Added by lyx2lyx',
+                                 r'\usepackage{varwidth}'])
+
+
+frontispiece_def = [
+    r'### Inserted by lyx2lyx (frontispiece layout) ###',
+    r'Style Frontispiece',
+    r'  CopyStyle             Titlehead',
+    r'  LatexName             frontispiece',
+    r'End',
+]
+
+
+def convert_koma_frontispiece(document):
+    """Remove local KOMA frontispiece definition"""
+    if document.textclass[:3] != "scr":
+        return
+
+    if document.del_local_layout(frontispiece_def):
+        document.add_module("ruby")
+
+
+def revert_koma_frontispiece(document):
+    """Add local KOMA frontispiece definition"""
+    if document.textclass[:3] != "scr":
+        return
+
+    if find_token(document.body, "\\begin_layout Frontispiece", 0) != -1:
+        document.append_local_layout(frontispiece_def)
+
+
+def revert_spellchecker_ignore(document):
+    """Revert document spellchecker dictionary"""
+    while True:
+        i = find_token(document.header, "\\spellchecker_ignore")
+        if i == -1:
+            return
         del document.header[i]
 
 
+def revert_docbook_mathml_prefix(document):
+    """Revert the DocBook parameter to choose the prefix for the MathML name space"""
+    while True:
+        i = find_token(document.header, "\\docbook_mathml_prefix")
+        if i == -1:
+            return
+        del document.header[i]
+
+
+def revert_document_metadata(document):
+    """Revert document metadata"""
+    i = 0
+    while True:
+        i = find_token(document.header, "\\begin_metadata", i)
+        if i == -1:
+            return
+        j = find_end_of(document.header, i, "\\begin_metadata", "\\end_metadata")
+        if j == -1:
+            # this should not happen
+            break
+        document.header[i : j + 1] = []
+
+
+def revert_index_macros(document):
+    " Revert inset index macros "
+
+    i = 0
+    while True:
+        # trailing blank needed here to exclude IndexMacro insets
+        i = find_token(document.body, '\\begin_inset Index ', i+1)
+        if i == -1:
+            break
+        j = find_end_of_inset(document.body, i)
+        if j == -1:
+            document.warning("Malformed LyX document: Can't find end of index inset at line %d" % i)
+            continue
+        pl = find_token(document.body, '\\begin_layout Plain Layout', i, j)
+        if pl == -1:
+            document.warning("Malformed LyX document: Can't find plain layout in index inset at line %d" % i)
+            continue
+        # find, store and remove inset params
+        pr = find_token(document.body, 'range', i, pl)
+        prval = get_quoted_value(document.body, "range", pr)
+        pagerange = ""
+        if prval == "start":
+            pagerange = "("
+        elif prval == "end":
+            pagerange = ")"
+        pf = find_token(document.body, 'pageformat', i, pl)
+        pageformat = get_quoted_value(document.body, "pageformat", pf)
+        del document.body[pr:pf+1]
+        # Now re-find (potentially moved) inset end again, and search for subinsets
+        j = find_end_of_inset(document.body, i)
+        if j == -1:
+            document.warning("Malformed LyX document: Can't find end of index inset at line %d" % i)
+            continue
+        # We search for all possible subentries in turn, store their
+        # content and delete them
+        see = []
+        seealso = []
+        subentry = []
+        subentry2 = []
+        sortkey = []
+        # Two subentries are allowed, thus the duplication
+        imacros = ["seealso", "see", "subentry", "subentry", "sortkey"]
+        for imacro in imacros:
+            iim = find_token(document.body, "\\begin_inset IndexMacro %s" % imacro, i, j)
+            if iim == -1:
+                continue
+            iime = find_end_of_inset(document.body, iim)
+            if iime == -1:
+                document.warning("Malformed LyX document: Can't find end of index macro inset at line %d" % i)
+                continue
+            iimpl = find_token(document.body, '\\begin_layout Plain Layout', iim, iime)
+            if iimpl == -1:
+                document.warning("Malformed LyX document: Can't find plain layout in index macro inset at line %d" % i)
+                continue
+            iimple = find_end_of_layout(document.body, iimpl)
+            if iimple == -1:
+                document.warning("Malformed LyX document: Can't find end of index macro inset plain layout at line %d" % i)
+                continue
+            icont = document.body[iimpl:iimple]
+            if imacro == "seealso":
+                seealso = icont[1:]
+            elif imacro == "see":
+                see = icont[1:]
+            elif imacro == "subentry":
+                # subentries might hace their own sortkey!
+                xiim = find_token(document.body, "\\begin_inset IndexMacro sortkey", iimpl, iimple)
+                if xiim != -1:
+                    xiime = find_end_of_inset(document.body, xiim)
+                    if xiime == -1:
+                        document.warning("Malformed LyX document: Can't find end of index macro inset at line %d" % i)
+                    else:
+                        xiimpl = find_token(document.body, '\\begin_layout Plain Layout', xiim, xiime)
+                        if xiimpl == -1:
+                            document.warning("Malformed LyX document: Can't find plain layout in index macro inset at line %d" % i)
+                        else:
+                            xiimple = find_end_of_layout(document.body, xiimpl)
+                            if xiimple == -1:
+                                document.warning("Malformed LyX document: Can't find end of index macro inset plain layout at line %d" % i)
+                            else:
+                                xicont = document.body[xiimpl:xiimple]
+                                xxicont = document.body[iimpl:xiimpl] + document.body[xiimple+1:iimple]
+                                icont = xicont + put_cmd_in_ert("@") + xxicont[1:]
+                if len(subentry) > 0:
+                    subentry2 = icont[1:]
+                else:
+                    subentry = icont[1:]
+            elif imacro == "sortkey":
+                sortkey = icont
+            # Everything stored. Delete subinset.
+            del document.body[iim:iime+1]
+            # Again re-find (potentially moved) index inset end
+            j = find_end_of_inset(document.body, i)
+            if j == -1:
+                document.warning("Malformed LyX document: Can't find end of index inset at line %d" % i)
+                continue
+        # Now insert all stuff, starting from the inset end
+        pl = find_token(document.body, '\\begin_layout Plain Layout', i, j)
+        if pl == -1:
+            document.warning("Malformed LyX document: Can't find plain layout in index inset at line %d" % i)
+            continue
+        ple = find_end_of_layout(document.body, pl)
+        if ple == -1:
+            document.warning("Malformed LyX document: Can't find end of index macro inset plain layout at line %d" % i)
+            continue
+        if len(see) > 0:
+            document.body[ple:ple] = put_cmd_in_ert("|" + pagerange + "see{") + see + put_cmd_in_ert("}")
+        elif len(seealso) > 0:
+            document.body[ple:ple] = put_cmd_in_ert("|" + pagerange + "seealso{") + seealso + put_cmd_in_ert("}")
+        elif pageformat != "default":
+            document.body[ple:ple] = put_cmd_in_ert("|" + pagerange + pageformat)
+        if len(subentry2) > 0:
+            document.body[ple:ple] = put_cmd_in_ert("!") + subentry2
+        if len(subentry) > 0:
+            document.body[ple:ple] = put_cmd_in_ert("!") + subentry
+        if len(sortkey) > 0:
+            document.body[pl:pl+1] = document.body[pl:pl] + sortkey + put_cmd_in_ert("@")
+            
+
 ##
 # Conversion hub
 #
@@ -3995,11 +4606,36 @@ convert = [
            [595, []],
            [596, [convert_parskip]],
            [597, [convert_libertinus_rm_fonts]],
-           [598, [convert_docbook_table_output]]
+           [598, []],
+           [599, []],
+           [600, []],
+           [601, [convert_math_refs]],
+           [602, [convert_branch_colors]],
+           [603, []],
+           [604, []],
+           [605, [convert_vcolumns2]],
+           [606, [convert_koma_frontispiece]],
+           [607, []],
+           [608, []],
+           [609, []],
+           [610, []]
           ]
 
-revert =  [[597, [revert_docbook_table_output]],
-           [595, [revert_libertinus_rm_fonts,revert_libertinus_sftt_fonts]],
+revert =  [[609, [revert_index_macros]],
+           [608, [revert_document_metadata]],
+           [607, [revert_docbook_mathml_prefix]],
+           [606, [revert_spellchecker_ignore]],
+           [605, [revert_koma_frontispiece]],
+           [604, [revert_vcolumns2]],
+           [603, [revert_branch_darkcols]],
+           [602, [revert_darkmode_graphics]],
+           [601, [revert_branch_colors]],
+           [600, []],
+           [599, [revert_math_refs]],
+           [598, [revert_hrquotes]],
+           [598, [revert_nopagebreak]],
+           [597, [revert_docbook_table_output]],
+           [596, [revert_libertinus_rm_fonts,revert_libertinus_sftt_fonts]],
            [595, [revert_parskip,revert_line_vspaces]],
            [594, [revert_ams_spaces]],
            [593, [revert_counter_inset]],