]> git.lyx.org Git - lyx.git/blobdiff - lib/lyx2lyx/lyx_2_2.py
Simplify a bunch of tests in lyx2lyx code.
[lyx.git] / lib / lyx2lyx / lyx_2_2.py
index a09ad2234044fef2b4325d7e5994582e6d287c01..c4121c13422b7e2bf68ae8a91439293c5e710de9 100644 (file)
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 # This file is part of lyx2lyx
 # -*- coding: utf-8 -*-
-# Copyright (C) 2011 The LyX team
+# Copyright (C) 2015 The LyX team
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -31,7 +31,7 @@ import sys, os
 #  del_token, check_token, get_option_value
 
 from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, lyx2latex, \
-  length_in_bp#, \
+  length_in_bp
 #  insert_to_preamble, latex_length, revert_flex_inset, \
 #  revert_font_attrs, hex2ratio, str2bool
 
@@ -39,6 +39,65 @@ from parser_tools import find_token, find_token_backwards, find_re, \
      find_end_of_inset, find_end_of_layout, find_nonempty_line, \
      get_containing_layout, get_value, check_token
 
+####################################################################
+# Private helper functions
+
+def revert_Argument_to_TeX_brace(document, line, endline, n, nmax, environment, opt, nolastopt):
+    '''
+    Reverts an InsetArgument to TeX-code
+    usage:
+    revert_Argument_to_TeX_brace(document, LineOfBegin, LineOfEnd, StartArgument, EndArgument, isEnvironment, isOpt, notLastOpt)
+    LineOfBegin is the line  of the \begin_layout or \begin_inset statement
+    LineOfEnd is the line  of the \end_layout or \end_inset statement, if "0" is given, the end of the file is used instead
+    StartArgument is the number of the first argument that needs to be converted
+    EndArgument is the number of the last argument that needs to be converted or the last defined one
+    isEnvironment must be true, if the layout is for a LaTeX environment
+    isOpt must be true, if the argument is an optional one
+    notLastOpt must be true if the argument is mandatory and followed by optional ones
+    '''
+    lineArg = 0
+    wasOpt = False
+    while lineArg != -1 and n < nmax + 1:
+      lineArg = find_token(document.body, "\\begin_inset Argument " + str(n), line)
+      if lineArg > endline and endline != 0:
+        return wasOpt
+      if lineArg != -1:
+        beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
+        # we have to assure that no other inset is in the Argument
+        beginInset = find_token(document.body, "\\begin_inset", beginPlain)
+        endInset = find_token(document.body, "\\end_inset", beginPlain)
+        k = beginPlain + 1
+        l = k
+        while beginInset < endInset and beginInset != -1:
+          beginInset = find_token(document.body, "\\begin_inset", k)
+          endInset = find_token(document.body, "\\end_inset", l)
+          k = beginInset + 1
+          l = endInset + 1
+        if environment == False:
+          if opt == False:
+            if nolastopt == False:
+              document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}{")
+            else:
+              document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}") 
+            del(document.body[lineArg : beginPlain + 1])
+            wasOpt = False
+          else:
+            document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("]")
+            document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("[")
+            wasOpt = True
+        else:
+          if opt == False:
+            document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}")
+            document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("{")
+            wasOpt = False
+          else:
+            document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("]")
+            document.body[lineArg : beginPlain + 1] = put_cmd_in_ert("[")
+            wasOpt = True
+        n += 1
+    return wasOpt
+
+
 ###############################################################################
 ###
 ### Conversion and reversion routines
@@ -252,11 +311,11 @@ def revert_smash(document):
     i = find_token(document.header, "\\use_package amsmath", 0)
     if i == -1:
         document.warning("Malformed LyX document: Can't find \\use_package amsmath.")
-        return;
+        return
     value = get_value(document.header, "\\use_package amsmath", i).split()[1]
     if value != "1":
         # nothing to do if package is not auto but on or off
-        return;
+        return
     j = 0
     while True:
         j = find_token(document.body, '\\begin_inset Formula', j)
@@ -427,14 +486,7 @@ def revert_question_env(document):
     """
 
     # Do we use theorems-ams-extended-bytype module?
-    have_mod = False
-    mods = document.get_module_list()
-    for mod in mods:
-        if mod == "theorems-ams-extended-bytype":
-            have_mod = True
-            continue
-
-    if not have_mod:
+    if not "theorems-ams-extended-bytype" in document.get_module_list():
         return
 
     consecutive = False
@@ -739,15 +791,7 @@ def revert_sigplan_doi(document):
 def revert_ex_itemargs(document):
     " Reverts \\item arguments of the example environments (Linguistics module) to TeX-code "
 
-    # Do we use the linguistics module?
-    have_mod = False
-    mods = document.get_module_list()
-    for mod in mods:
-        if mod == "linguistics":
-            have_mod = True
-            continue
-
-    if not have_mod:
+    if not "linguistics" in document.get_module_list():
         return
 
     i = 0
@@ -778,15 +822,7 @@ def revert_ex_itemargs(document):
 def revert_forest(document):
     " Reverts the forest environment (Linguistics module) to TeX-code "
 
-    # Do we use the linguistics module?
-    have_mod = False
-    mods = document.get_module_list()
-    for mod in mods:
-        if mod == "linguistics":
-            have_mod = True
-            continue
-
-    if not have_mod:
+    if not "linguistics" in document.get_module_list():
         return
 
     i = 0
@@ -817,15 +853,7 @@ def revert_forest(document):
 def revert_glossgroup(document):
     " Reverts the GroupGlossedWords inset (Linguistics module) to TeX-code "
 
-    # Do we use the linguistics module?
-    have_mod = False
-    mods = document.get_module_list()
-    for mod in mods:
-        if mod == "linguistics":
-            have_mod = True
-            continue
-
-    if not have_mod:
+    if not "linguistics" in document.get_module_list():
         return
 
     i = 0
@@ -842,7 +870,6 @@ def revert_glossgroup(document):
         beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
         endPlain = find_end_of_layout(document.body, beginPlain)
         content = lyx2latex(document, document.body[beginPlain : endPlain])
-        document.warning("content: %s" % content)
 
         document.body[i:j + 1] = ["{", "", content, "", "}"]
         # no need to reset i
@@ -851,15 +878,7 @@ def revert_glossgroup(document):
 def revert_newgloss(document):
     " Reverts the new Glosse insets (Linguistics module) to the old format "
 
-    # Do we use the linguistics module?
-    have_mod = False
-    mods = document.get_module_list()
-    for mod in mods:
-        if mod == "linguistics":
-            have_mod = True
-            continue
-
-    if not have_mod:
+    if not "linguistics" in document.get_module_list():
         return
 
     glosses = ("\\begin_inset Flex Glosse", "\\begin_inset Flex Tri-Glosse")
@@ -907,15 +926,7 @@ def revert_newgloss(document):
 def convert_newgloss(document):
     " Converts Glosse insets (Linguistics module) to the new format "
 
-    # Do we use the linguistics module?
-    have_mod = False
-    mods = document.get_module_list()
-    for mod in mods:
-        if mod == "linguistics":
-            have_mod = True
-            continue
-
-    if not have_mod:
+    if not "linguistics" in document.get_module_list():
         return
 
     glosses = ("\\begin_inset Flex Glosse", "\\begin_inset Flex Tri-Glosse")
@@ -1028,11 +1039,30 @@ def convert_origin(document):
     i = find_token(document.header, "\\textclass ", 0)
     if i == -1:
         document.warning("Malformed LyX document: No \\textclass!!")
-        return;
+        return
     if document.dir == "":
         origin = "stdin"
     else:
-        origin = document.dir.replace('\\', '/') + '/'
+        relpath = ''
+        if document.systemlyxdir and document.systemlyxdir != '':
+            try:
+                if os.path.isabs(document.dir):
+                    absdir = os.path.normpath(document.dir)
+                else:
+                    absdir = os.path.normpath(os.path.abspath(document.dir))
+                if os.path.isabs(document.systemlyxdir):
+                    abssys = os.path.normpath(document.systemlyxdir)
+                else:
+                    abssys = os.path.normpath(os.path.abspath(document.systemlyxdir))
+                relpath = os.path.relpath(absdir, abssys)
+                if relpath.find('..') == 0:
+                    relpath = ''
+            except:
+                relpath = ''
+        if relpath == '':
+            origin = document.dir.replace('\\', '/') + '/'
+        else:
+            origin = os.path.join("/systemlyxdir", relpath).replace('\\', '/') + '/'
         if os.name != 'nt':
             origin = unicode(origin, sys.getfilesystemencoding())
     document.header[i:i] = ["\\origin " + origin]
@@ -1044,7 +1074,7 @@ def revert_origin(document):
     i = find_token(document.header, "\\origin ", 0)
     if i == -1:
         document.warning("Malformed LyX document: No \\origin!!")
-        return;
+        return
     del document.header[i]
 
 
@@ -1128,16 +1158,16 @@ def revert_colorbox(document):
 
         beg = document.body[frame].find('"')
         end = document.body[frame].rfind('"')
-        framecolor = document.body[frame][beg+1:end]
+        framecolor = document.body[frame][beg + 1 : end]
 
         # this should be on the next line
         bgcolor = frame + 1
         beg = document.body[bgcolor].find('"')
         end = document.body[bgcolor].rfind('"')
-        backcolor = document.body[bgcolor][beg+1:end]
+        backcolor = document.body[bgcolor][beg + 1 : end]
 
         # delete those bits
-        del document.body[frame:frame+2]
+        del document.body[frame : frame + 2]
         # adjust end of inset
         einset -= 2
 
@@ -1151,11 +1181,13 @@ def revert_colorbox(document):
             # nothing needed
             pass
         else:
+            # we also neeed to load xcolor in the preamble but only once
+            add_to_preamble(document, ["\\@ifundefined{rangeHsb}{\usepackage{xcolor}}{}"])
             document.body[einset + 1 : einset + 1] = put_cmd_in_ert("}")
             if framecolor != defaultframecolor:
-                document.body[binset:binset] = put_cmd_in_ert("\\backslash fcolorbox{" + framecolor + "}{" + backcolor + "}{")
+                document.body[binset:binset] = put_cmd_in_ert("\\fcolorbox{" + framecolor + "}{" + backcolor + "}{")
             else:
-              document.body[binset:binset] = put_cmd_in_ert("\\backslash colorbox{" + backcolor + "}{")
+              document.body[binset:binset] = put_cmd_in_ert("\\colorbox{" + backcolor + "}{")
 
         binset = einset
 
@@ -1566,6 +1598,541 @@ def revert_external_bbox(document):
     convert_revert_external_bbox(document, False)
 
 
+def revert_tcolorbox_1(document):
+  " Reverts the Flex:Subtitle inset of tcolorbox to TeX-code "
+  i = -1
+  while True:
+    i = find_token(document.header, "tcolorbox", i)
+    if i == -1:
+      break
+    else:    
+      flex = 0
+      flexEnd = -1
+      flex = find_token(document.body, "\\begin_inset Flex Subtitle", flex)
+      if flex == -1:
+        return flexEnd
+      flexEnd = find_end_of_inset(document.body, flex)
+      wasOpt = revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, False, True, False)
+      revert_Argument_to_TeX_brace(document, flex, 0, 2, 2, False, False, False)
+      flexEnd = find_end_of_inset(document.body, flex)
+      if wasOpt == True:
+        document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\tcbsubtitle")
+      else:
+        document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\tcbsubtitle{")
+      document.body[flexEnd + 4 : flexEnd + 7] = put_cmd_in_ert("}")
+      flex += 1
+
+
+def revert_tcolorbox_2(document):
+  " Reverts the Flex:Raster_Color_Box inset of tcolorbox to TeX-code "
+  i = -1
+  while True:
+    i = find_token(document.header, "tcolorbox", i)
+    if i == -1:
+      break
+    else:    
+      flex = 0
+      flexEnd = -1
+      flex = find_token(document.body, "\\begin_inset Flex Raster Color Box", flex)
+      if flex == -1:
+        return flexEnd
+      flexEnd = find_end_of_inset(document.body, flex)
+      revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, True, True, False)
+      flexEnd = find_end_of_inset(document.body, flex)
+      document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\begin{tcbraster}")
+      document.body[flexEnd + 4 : flexEnd + 7] = put_cmd_in_ert("\\end{tcbraster}")
+      flex += 1
+
+
+def revert_tcolorbox_3(document):
+  " Reverts the Flex:Custom_Color_Box_1 inset of tcolorbox to TeX-code "
+  i = -1
+  while True:
+    i = find_token(document.header, "tcolorbox", i)
+    if i == -1:
+      break
+    else:    
+      flex = 0
+      flexEnd = -1
+      flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 1", flex)
+      if flex == -1:
+        return flexEnd
+      flexEnd = find_end_of_inset(document.body, flex)
+      revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, True, True, False)
+      revert_Argument_to_TeX_brace(document, flex, 0, 2, 2, True, False, False)
+      flexEnd = find_end_of_inset(document.body, flex)
+      document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\begin{cBoxA}")
+      document.body[flexEnd + 4 : flexEnd + 7] = put_cmd_in_ert("{}\\end{cBoxA}")
+      flex += 1
+
+
+def revert_tcolorbox_4(document):
+  " Reverts the Flex:Custom_Color_Box_2 inset of tcolorbox to TeX-code "
+  i = -1
+  while True:
+    i = find_token(document.header, "tcolorbox", i)
+    if i == -1:
+      break
+    else:    
+      flex = 0
+      flexEnd = -1
+      flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 2", flex)
+      if flex == -1:
+        return flexEnd
+      flexEnd = find_end_of_inset(document.body, flex)
+      revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, True, True, False)
+      revert_Argument_to_TeX_brace(document, flex, 0, 2, 2, True, False, False)
+      flexEnd = find_end_of_inset(document.body, flex)
+      document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\begin{cBoxB}")
+      document.body[flexEnd + 4 : flexEnd + 7] = put_cmd_in_ert("{}\\end{cBoxB}")
+      flex += 1
+
+
+def revert_tcolorbox_5(document):
+  " Reverts the Flex:Custom_Color_Box_3 inset of tcolorbox to TeX-code "
+  i = -1
+  while True:
+    i = find_token(document.header, "tcolorbox", i)
+    if i == -1:
+      break
+    else:    
+      flex = 0
+      flexEnd = -1
+      flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 3", flex)
+      if flex == -1:
+        return flexEnd
+      flexEnd = find_end_of_inset(document.body, flex)
+      revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, True, True, False)
+      revert_Argument_to_TeX_brace(document, flex, 0, 2, 2, True, False, False)
+      flexEnd = find_end_of_inset(document.body, flex)
+      document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\begin{cBoxC}")
+      document.body[flexEnd + 4 : flexEnd + 7] = put_cmd_in_ert("{}\\end{cBoxC}")
+      flex += 1
+
+
+def revert_tcolorbox_6(document):
+  " Reverts the Flex:Custom_Color_Box_4 inset of tcolorbox to TeX-code "
+  i = -1
+  while True:
+    i = find_token(document.header, "tcolorbox", i)
+    if i == -1:
+      break
+    else:    
+      flex = 0
+      flexEnd = -1
+      flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 4", flex)
+      if flex == -1:
+        return flexEnd
+      flexEnd = find_end_of_inset(document.body, flex)
+      revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, True, True, False)
+      revert_Argument_to_TeX_brace(document, flex, 0, 2, 2, True, False, False)
+      flexEnd = find_end_of_inset(document.body, flex)
+      document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\begin{cBoxD}")
+      document.body[flexEnd + 4 : flexEnd + 7] = put_cmd_in_ert("{}\\end{cBoxD}")
+      flex += 1
+
+
+def revert_tcolorbox_7(document):
+  " Reverts the Flex:Custom_Color_Box_5 inset of tcolorbox to TeX-code "
+  i = -1
+  while True:
+    i = find_token(document.header, "tcolorbox", i)
+    if i == -1:
+      break
+    else:    
+      flex = 0
+      flexEnd = -1
+      flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 5", flex)
+      if flex == -1:
+        return flexEnd
+      flexEnd = find_end_of_inset(document.body, flex)
+      revert_Argument_to_TeX_brace(document, flex, flexEnd, 1, 1, True, True, False)
+      revert_Argument_to_TeX_brace(document, flex, 0, 2, 2, True, False, False)
+      flexEnd = find_end_of_inset(document.body, flex)
+      document.body[flex + 0 : flex + 4] = put_cmd_in_ert("\\begin{cBoxE}")
+      document.body[flexEnd + 4 : flexEnd + 7] = put_cmd_in_ert("{}\\end{cBoxE}")
+      flex += 1
+
+
+def revert_tcolorbox_8(document):
+  " Reverts the layout New Color Box Type of tcolorbox to TeX-code "
+  i = 0
+  j = 0
+  k = 0
+  while True:
+    if i != -1:
+      i = find_token(document.body, "\\begin_layout New Color Box Type", i)
+    if i != -1:
+      j = find_end_of_layout(document.body, i)
+      wasOpt = revert_Argument_to_TeX_brace(document, i, j, 1, 1, False, True, False)
+      revert_Argument_to_TeX_brace(document, i, 0, 2, 2, False, False, True)
+      revert_Argument_to_TeX_brace(document, i, 0, 3, 4, False, True, False)
+      document.body[i] = document.body[i].replace("\\begin_layout New Color Box Type", "\\begin_layout Standard")
+      if wasOpt == True:
+        document.body[i + 1 : i + 1] = put_cmd_in_ert("\\newtcolorbox")
+      else:
+        document.body[i + 1 : i + 1] = put_cmd_in_ert("\\newtcolorbox{")
+      k = find_end_of_inset(document.body, j)
+      k = find_token(document.body, "\\end_inset", k + 1)
+      k = find_token(document.body, "\\end_inset", k + 1)
+      if wasOpt == True:
+        k = find_token(document.body, "\\end_inset", k + 1)
+      document.body[k + 2 : j + 2] = put_cmd_in_ert("{")
+      j = find_token(document.body, "\\begin_layout Standard", j + 1)
+      document.body[j - 2 : j - 2] = put_cmd_in_ert("}")
+      i += 1
+    if i == -1:
+      return
+
+
+def revert_moderncv_1(document):
+  " Reverts the new inset of moderncv to TeX-code in preamble "
+  
+  if document.textclass != "moderncv":
+    return
+  i = 0
+  j = 0
+  lineArg = 0
+  while True:
+    # at first revert the new styles
+    # \moderncvicons
+    i = find_token(document.body, "\\begin_layout CVIcons", 0)
+    if i == -1:
+      return
+    j = find_end_of_layout(document.body, i)
+    if j == -1:
+      document.warning("Malformed LyX document: Can't find end of CVIcons layout")
+      i += 1
+      continue
+    content = lyx2latex(document, document.body[i:j + 1])
+    add_to_preamble(document, ["\\moderncvicons{" + content + "}"])
+    del document.body[i:j + 1]
+    # \hintscolumnwidth
+    i = find_token(document.body, "\\begin_layout CVColumnWidth", 0)
+    if i == -1:
+      return
+    j = find_end_of_layout(document.body, i)
+    if j == -1:
+      document.warning("Malformed LyX document: Can't find end of CVColumnWidth layout")
+      i += 1
+      continue
+    content = lyx2latex(document, document.body[i:j + 1])
+    add_to_preamble(document, ["\\setlength{\hintscolumnwidth}{" + content + "}"])
+    del document.body[i:j + 1]
+    # now change the new styles to the obsolete ones
+    # \name
+    i = find_token(document.body, "\\begin_layout Name", 0)
+    if i == -1:
+      return
+    j = find_end_of_layout(document.body, i)
+    if j == -1:
+      document.warning("Malformed LyX document: Can't find end of Name layout")
+      i += 1
+      continue
+    lineArg = find_token(document.body, "\\begin_inset Argument 1", i)
+    if lineArg > j and j != 0:
+      return
+    if lineArg != -1:
+      beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
+      # we have to assure that no other inset is in the Argument
+      beginInset = find_token(document.body, "\\begin_inset", beginPlain)
+      endInset = find_token(document.body, "\\end_inset", beginPlain)
+      k = beginPlain + 1
+      l = k
+      while beginInset < endInset and beginInset != -1:
+        beginInset = find_token(document.body, "\\begin_inset", k)
+        endInset = find_token(document.body, "\\end_inset", l)
+        k = beginInset + 1
+        l = endInset + 1
+      Arg2 = document.body[l + 5 : l + 6]
+      # rename the style
+      document.body[i : i + 1]= ["\\begin_layout FirstName"]
+      # delete the Argument inset
+      del( document.body[endInset - 2 : endInset + 3])
+      del( document.body[lineArg : beginPlain + 1])
+      document.body[i + 4 : i + 4]= ["\\begin_layout FamilyName"] + Arg2 + ["\\end_layout"] + [""]
+
+
+def revert_moderncv_2(document):
+  " Reverts the phone inset of moderncv to the obsoleted mobile or fax "
+  
+  if document.textclass != "moderncv":
+    return
+  i = 0
+  j = 0
+  lineArg = 0
+  while True:
+    # \phone
+    i = find_token(document.body, "\\begin_layout Phone", i)
+    if i == -1:
+      return
+    j = find_end_of_layout(document.body, i)
+    if j == -1:
+      document.warning("Malformed LyX document: Can't find end of Phone layout")
+      i += 1
+      return
+    lineArg = find_token(document.body, "\\begin_inset Argument 1", i)
+    if lineArg > j and j != 0:
+      i += 1
+      continue
+    if lineArg != -1:
+      beginPlain = find_token(document.body, "\\begin_layout Plain Layout", lineArg)
+      # we have to assure that no other inset is in the Argument
+      beginInset = find_token(document.body, "\\begin_inset", beginPlain)
+      endInset = find_token(document.body, "\\end_inset", beginPlain)
+      k = beginPlain + 1
+      l = k
+      while beginInset < endInset and beginInset != -1:
+        beginInset = find_token(document.body, "\\begin_inset", k)
+        endInset = find_token(document.body, "\\end_inset", l)
+        k = beginInset + 1
+        l = endInset + 1
+      Arg = document.body[beginPlain + 1 : beginPlain + 2]
+      # rename the style
+      if Arg[0] == "mobile":
+        document.body[i : i + 1]= ["\\begin_layout Mobile"]
+      if Arg[0] == "fax":
+        document.body[i : i + 1]= ["\\begin_layout Fax"]
+      # delete the Argument inset
+      del(document.body[endInset - 2 : endInset + 1])
+      del(document.body[lineArg : beginPlain + 3])
+    i += 1
+
+
+def convert_moderncv(document):
+  " Convert the Fax and Mobile inset of moderncv to the new phone inset "
+  
+  if document.textclass != "moderncv":
+    return
+  i = 0
+  j = 0
+  lineArg = 0
+  while True:
+    # \mobile
+    i = find_token(document.body, "\\begin_layout Mobile", i)
+    if i == -1:
+      return
+    j = find_end_of_layout(document.body, i)
+    if j == -1:
+      document.warning("Malformed LyX document: Can't find end of Mobile layout")
+      i += 1
+      return
+    document.body[i + 1 : i + 1] = ["\\begin_inset Argument 1", "status open", "",
+                        "\\begin_layout Plain Layout", "mobile", "\\end_layout", "",
+                        "\\end_inset", ""]
+    # \fax
+    i = find_token(document.body, "\\begin_layout Fax", i)
+    if i == -1:
+      return
+    j = find_end_of_layout(document.body, i)
+    if j == -1:
+      document.warning("Malformed LyX document: Can't find end of Fax layout")
+      i += 1
+      return
+    document.body[i + 1 : i + 1] = ["\\begin_inset Argument 1", "status open", "",
+                        "\\begin_layout Plain Layout", "fax", "\\end_layout", "",
+                        "\\end_inset", ""]
+    # \firstname and \familyname
+    i1 = find_token(document.body, "\\begin_layout FirstName", 0)
+    if i1 == -1:
+      return
+    j1 = find_end_of_layout(document.body, i1)
+    if j1 == -1:
+      document.warning("Malformed LyX document: Can't find end of FirstName layout")
+      i1 += 1
+      return
+    FirstName = document.body[i1 + 1 : i1 + 2]
+    i2 = find_token(document.body, "\\begin_layout FamilyName", 0)
+    if i2 == -1:
+      return
+    j2 = find_end_of_layout(document.body, i2)
+    if j2 == -1:
+      document.warning("Malformed LyX document: Can't find end of FamilyName layout")
+      i2 += 1
+      return
+    FamilyName = document.body[i2 + 1 : i2 + 2]
+    if j1 > j2:
+      k = j1
+      l = i2
+    else:
+      k = j2
+      l = i1
+    document.body[k + 1 : k + 1] = ["\\begin_layout Name", "\\begin_inset Argument 1", "status open", "",
+                        "\\begin_layout Plain Layout", FirstName[0], "\\end_layout", "",
+                        "\\end_inset", "", FamilyName[0], "\\end_layout", ""]
+    #document.body[i2 + 1 : i2 + 1] = ["hellok: ", str(k)]
+    del(document.body[l : k])
+    i += 1
+    i1 += 1
+    i2 += 1
+
+
+def revert_achemso(document):
+  " Reverts the flex inset Latin to TeX code "
+  
+  if document.textclass != "achemso":
+    return
+  i = 0
+  j = 0
+  while True:
+    i = find_token(document.body, "\\begin_inset Flex Latin", i)
+    if i != -1:
+      j = find_end_of_inset(document.body, i)
+    else:
+      return
+    if j != -1:
+      beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
+      endPlain = find_end_of_layout(document.body, beginPlain)
+      content = lyx2latex(document, document.body[beginPlain : endPlain])
+      document.body[i:j + 1] = put_cmd_in_ert("\\latin{" + content + "}")
+    else:
+      document.warning("Malformed LyX document: Can't find end of flex inset Latin")
+      return
+    i += 1
+
+
+fontsettings = ["\\font_roman", "\\font_sans", "\\font_typewriter", "\\font_math", \
+                "\\font_sf_scale", "\\font_tt_scale"]
+fontdefaults = ["default", "default", "default", "auto", "100", "100"]
+fontquotes = [True, True, True, True, False, False]
+
+def convert_fontsettings(document):
+    " Duplicate font settings "
+
+    i = find_token(document.header, "\\use_non_tex_fonts ", 0)
+    if i == -1:
+        document.warning("Malformed LyX document: No \\use_non_tex_fonts!")
+        use_non_tex_fonts = "false"
+    else:
+        use_non_tex_fonts = get_value(document.header, "\\use_non_tex_fonts", i)
+    j = 0
+    for f in fontsettings:
+        i = find_token(document.header, f + " ", 0)
+        if i == -1:
+            document.warning("Malformed LyX document: No " + f + "!")
+            j = j + 1
+            continue
+        value = document.header[i][len(f):].strip()
+        if fontquotes[j]:
+            if use_non_tex_fonts == "true":
+                document.header[i:i+1] = [f + ' "' + fontdefaults[j] + '" "' + value + '"']
+            else:
+                document.header[i:i+1] = [f + ' "' + value + '" "' + fontdefaults[j] + '"']
+        else:
+            if use_non_tex_fonts == "true":
+                document.header[i:i+1] = [f + ' ' + fontdefaults[j] + ' ' + value]
+            else:
+                document.header[i:i+1] = [f + ' ' + value + ' ' + fontdefaults[j]]
+        j = j + 1
+
+
+def revert_fontsettings(document):
+    " Merge font settings "
+
+    i = find_token(document.header, "\\use_non_tex_fonts ", 0)
+    if i == -1:
+        document.warning("Malformed LyX document: No \\use_non_tex_fonts!")
+        use_non_tex_fonts = "false"
+    else:
+        use_non_tex_fonts = get_value(document.header, "\\use_non_tex_fonts", i)
+    j = 0
+    for f in fontsettings:
+        i = find_token(document.header, f + " ", 0)
+        if i == -1:
+            document.warning("Malformed LyX document: No " + f + "!")
+            j = j + 1
+            continue
+        line = get_value(document.header, f, i)
+        if fontquotes[j]:
+            q1 = line.find('"')
+            q2 = line.find('"', q1+1)
+            q3 = line.find('"', q2+1)
+            q4 = line.find('"', q3+1)
+            if q1 == -1 or q2 == -1 or q3 == -1 or q4 == -1:
+                document.warning("Malformed LyX document: Missing quotes!")
+                j = j + 1
+                continue
+            if use_non_tex_fonts == "true":
+                document.header[i:i+1] = [f + ' ' + line[q3+1:q4]]
+            else:
+                document.header[i:i+1] = [f + ' ' + line[q1+1:q2]]
+        else:
+            if use_non_tex_fonts == "true":
+                document.header[i:i+1] = [f + ' ' + line.split()[1]]
+            else:
+                document.header[i:i+1] = [f + ' ' + line.split()[0]]
+        j = j + 1
+
+
+def revert_solution(document):
+    " Reverts the solution environment of the theorem module to TeX code "
+
+    # Do we use one of the modules that provides Solution?
+    have_mod = False
+    mods = document.get_module_list()
+    for mod in mods:
+        if mod == "theorems-std" or mod == "theorems-bytype" \
+        or mod == "theorems-ams" or mod == "theorems-ams-bytype":
+            have_mod = True
+            break
+    if not have_mod:
+        return
+
+    consecutive = False
+    is_starred = False
+    i = 0
+    while True:
+        i = find_token(document.body, "\\begin_layout Solution", i)
+        if i == -1:
+            return
+
+        is_starred = document.body[i].startswith("\\begin_layout Solution*")
+        if is_starred == True:
+            LaTeXName = "sol*"
+            LyXName = "Solution*"
+            theoremName = "newtheorem*"
+        else:
+            LaTeXName = "sol"
+            LyXName = "Solution"
+            theoremName = "newtheorem"
+
+        j = find_end_of_layout(document.body, i)
+        if j == -1:
+            document.warning("Malformed LyX document: Can't find end of " + LyXName + " layout")
+            i += 1
+            continue
+
+        # if this is not a consecutive env, add start command
+        begcmd = []
+        if not consecutive:
+            begcmd = put_cmd_in_ert("\\begin{%s}" % (LaTeXName))
+
+        # has this a consecutive theorem of same type?
+        consecutive = document.body[j + 2] == "\\begin_layout " + LyXName
+
+        # if this is not followed by a consecutive env, add end command
+        if not consecutive:
+            document.body[j : j + 1] = put_cmd_in_ert("\\end{%s}" % (LaTeXName)) + ["\\end_layout"]
+
+        document.body[i : i + 1] = ["\\begin_layout Standard", ""] + begcmd
+
+        add_to_preamble(document, "\\theoremstyle{definition}")
+        if is_starred or mod == "theorems-bytype" or mod == "theorems-ams-bytype":
+            add_to_preamble(document, "\\%s{%s}{\\protect\\solutionname}" % \
+                (theoremName, LaTeXName))
+        else: # mod == "theorems-std" or mod == "theorems-ams" and not is_starred
+            add_to_preamble(document, "\\%s{%s}[thm]{\\protect\\solutionname}" % \
+                (theoremName, LaTeXName))
+
+        add_to_preamble(document, "\\providecommand{\solutionname}{Solution}")
+        i = j
+
+
+def revert_verbatim_star(document):
+    from lyx_2_1 import revert_verbatim
+    revert_verbatim(document, True)
+
+
 ##
 # Conversion hub
 #
@@ -1597,10 +2164,24 @@ convert = [
            [494, []],
            [495, [convert_subref]],
            [496, [convert_nounzip]],
-           [497, [convert_external_bbox]]
+           [497, [convert_external_bbox]],
+           [498, []],
+           [499, [convert_moderncv]],
+           [500, []],
+           [501, [convert_fontsettings]],
+           [502, []],
+           [503, []]
           ]
 
 revert =  [
+           [502, [revert_verbatim_star]],
+           [501, [revert_solution]],
+           [500, [revert_fontsettings]],
+           [499, [revert_achemso]],
+           [498, [revert_moderncv_1, revert_moderncv_2]],
+           [497, [revert_tcolorbox_1, revert_tcolorbox_2,
+                  revert_tcolorbox_3, revert_tcolorbox_4, revert_tcolorbox_5,
+                  revert_tcolorbox_6, revert_tcolorbox_7, revert_tcolorbox_8]],
            [496, [revert_external_bbox]],
            [495, []], # nothing to do since the noUnzip parameter was optional
            [494, [revert_subref]],