commit 4eb3ed96e53ab0eb2af519caa6125cac79c823ad
Author: Richard Heck <rgh...@lyx.org>
Date:   Wed Jun 1 12:31:48 2016 -0400

    Update lyx2lyx from 2.2.0. This is in preparation for the 2.1.5 release.

diff --git a/lib/lyx2lyx/CMakeLists.txt b/lib/lyx2lyx/CMakeLists.txt
index 6cfa5cd..43fb13a 100644
--- a/lib/lyx2lyx/CMakeLists.txt
+++ b/lib/lyx2lyx/CMakeLists.txt
@@ -14,4 +14,10 @@ if (UNIX)
        # include(../PyCompile)
 endif()
 
+set(_testname "lyx2lyx/parser_tools")
+add_test(NAME ${_testname}
+  COMMAND ${LYX_PYTHON_EXECUTABLE} 
"${TOP_SRC_DIR}/lib/lyx2lyx/test_parser_tools.py"
+  )
+settestlabel(${_testname} "lyx2lyx")
+
 install(PROGRAMS ${TOP_SRC_DIR}/lib/lyx2lyx/lyx2lyx DESTINATION 
${LYX_DATA_SUBDIR}lyx2lyx)
diff --git a/lib/lyx2lyx/LyX.py b/lib/lyx2lyx/LyX.py
index 7e52238..1e2147d 100644
--- a/lib/lyx2lyx/LyX.py
+++ b/lib/lyx2lyx/LyX.py
@@ -1,6 +1,6 @@
 # This file is part of lyx2lyx
 # -*- coding: utf-8 -*-
-# Copyright (C) 2002-2011 The LyX Team
+# Copyright (C) 2002-2015 The LyX Team
 # Copyright (C) 2002-2004 Dekel Tsur <de...@lyx.org>
 # Copyright (C) 2002-2006 José Matos <jama...@lyx.org>
 #
@@ -33,7 +33,7 @@ try:
     import lyx2lyx_version
     version__ = lyx2lyx_version.version
 except: # we are running from build directory so assume the last version
-    version__ = '2.1'
+    version__ = '2.2'
 
 default_debug__ = 2
 
@@ -64,6 +64,7 @@ def minor_versions(major, last_minor_version):
 format_re = re.compile(r"(\d)[\.,]?(\d\d)")
 fileformat = re.compile(r"\\lyxformat\s*(\S*)")
 original_version = re.compile(r".*?LyX ([\d.]*)")
+original_tex2lyx_version = re.compile(r".*?tex2lyx ([\d.]*)")
 
 ##
 # file format information:
@@ -79,11 +80,13 @@ format_relation = [("0_06",    [200], minor_versions("0.6" 
, 4)),
                    ("1_1_6_3", [218], ["1.1", "1.1.6.3","1.1.6.4"]),
                    ("1_2",     [220], minor_versions("1.2" , 4)),
                    ("1_3",     [221], minor_versions("1.3" , 7)),
-                   ("1_4", range(222,246), minor_versions("1.4" , 5)),
-                   ("1_5", range(246,277), minor_versions("1.5" , 7)),
-                   ("1_6", range(277,346), minor_versions("1.6" , 10)),
-                   ("2_0", range(346,414), minor_versions("2.0", 8)),
-                   ("2_1", range(414,475), minor_versions("2.1", 0))
+                   # Note that range(i,j) is up to j *excluded*.
+                   ("1_4", list(range(222,246)), minor_versions("1.4" , 5)),
+                   ("1_5", list(range(246,277)), minor_versions("1.5" , 7)),
+                   ("1_6", list(range(277,346)), minor_versions("1.6" , 10)),
+                   ("2_0", list(range(346,414)), minor_versions("2.0" , 8)),
+                   ("2_1", list(range(414,475)), minor_versions("2.1" , 5)),
+                   ("2_2", list(range(475,509)), minor_versions("2.2" , 0))
                   ]
 
 ####################################################################
@@ -186,7 +189,8 @@ class LyX_base:
 
     def __init__(self, end_format = 0, input = "", output = "", error = "",
                  debug = default_debug__, try_hard = 0, cjk_encoding = '',
-                 final_version = "", language = "english", encoding = "auto"):
+                 final_version = "", systemlyxdir = '', language = "english",
+                 encoding = "auto"):
 
         """Arguments:
         end_format: final format that the file should be converted. (integer)
@@ -251,6 +255,7 @@ class LyX_base:
         self.status = 0
         self.encoding = encoding
         self.language = language
+        self.systemlyxdir = systemlyxdir
 
 
     def warning(self, message, debug_level= default_debug__):
@@ -415,12 +420,16 @@ class LyX_base:
                 return None
 
             line = line.replace("fix",".")
-            result = original_version.match(line)
+            # need to test original_tex2lyx_version first because tex2lyx
+            # writes "#LyX file created by tex2lyx 2.2"
+            result = original_tex2lyx_version.match(line)
+            if not result:
+                result = original_version.match(line)
+                if result:
+                    # Special know cases: reLyX and KLyX
+                    if line.find("reLyX") != -1 or line.find("KLyX") != -1:
+                        return "0.12"
             if result:
-                # Special know cases: reLyX and KLyX
-                if line.find("reLyX") != -1 or line.find("KLyX") != -1:
-                    return "0.12"
-
                 res = result.group(1)
                 if not res:
                     self.warning(line)
@@ -547,6 +556,11 @@ class LyX_base:
 
     def convert(self):
         "Convert from current (self.format) to self.end_format."
+        if self.format == self.end_format:
+            self.warning("No conversion needed: Target format %s "
+                "same as current format!" % self.format, default_debug__)
+            return
+
         mode, conversion_chain = self.chain()
         self.warning("conversion chain: " + str(conversion_chain), 3)
 
@@ -722,9 +736,10 @@ class File(LyX_base):
 
     def __init__(self, end_format = 0, input = "", output = "", error = "",
                  debug = default_debug__, try_hard = 0, cjk_encoding = '',
-                 final_version = ''):
+                 final_version = '', systemlyxdir = ''):
         LyX_base.__init__(self, end_format, input, output, error,
-                          debug, try_hard, cjk_encoding, final_version)
+                          debug, try_hard, cjk_encoding, final_version,
+                          systemlyxdir)
         self.read()
 
 
diff --git a/lib/lyx2lyx/Makefile.am b/lib/lyx2lyx/Makefile.am
index d2ed356..4490cb7 100644
--- a/lib/lyx2lyx/Makefile.am
+++ b/lib/lyx2lyx/Makefile.am
@@ -1,8 +1,8 @@
 include $(top_srcdir)/config/common.am
 
-CLEANFILES += *.pyc *.pyo
+CLEANFILES = *.pyc *.pyo
 
-EXTRA_DIST = lyx2lyx_version.py.in
+EXTRA_DIST = lyx2lyx_version.py.in test_parser_tools.py CMakeLists.txt
 
 CHMOD = chmod
 
@@ -32,8 +32,20 @@ dist_lyx2lyx_PYTHON = \
        lyx_1_6.py \
        lyx_2_0.py \
        lyx_2_1.py \
+       lyx_2_2.py \
        profiling.py \
        test_parser_tools.py
 
 install-data-hook:
        $(CHMOD) 755 $(DESTDIR)$(lyx2lyxdir)/lyx2lyx
+
+alltests: check alltests-recursive
+
+alltests-recursive:
+       @$(PYTHON) "$(srcdir)/test_parser_tools.py"; \
+       if test $$? -eq 0; then \
+               echo -e "=====================\nlyx2lyx tests 
passed.\n====================="; \
+       else \
+               echo -e "=====================\nlyx2lyx tests 
failed.\n====================="; \
+       fi
+
diff --git a/lib/lyx2lyx/generate_encoding_info.py 
b/lib/lyx2lyx/generate_encoding_info.py
index 6766ef0..50725b7 100644
--- a/lib/lyx2lyx/generate_encoding_info.py
+++ b/lib/lyx2lyx/generate_encoding_info.py
@@ -19,6 +19,7 @@
 """ This module parses lib/languages and prints it as a python
 dictionary, ready to use by other python modules"""
 
+from __future__ import print_function
 import pprint
 
 def parse_line(line):
@@ -55,8 +56,8 @@ if __name__ == '__main__':
             lang[tmp[0]] = tmp[1:]
 
 
-    print "# This file is generated by generate_incoding_info.py from 
lib/languages file."
-    print "# Do not change this file directly."
-    print
-    print "lang = ",
+    print ("# This file is generated by generate_incoding_info.py from 
lib/languages file.")
+    print ("# Do not change this file directly.")
+    print ()
+    print ("lang = ", end = " ")
     pprint.pprint(lang)
diff --git a/lib/lyx2lyx/lyx2lyx b/lib/lyx2lyx/lyx2lyx
index dbb3126..04b2302 100755
--- a/lib/lyx2lyx/lyx2lyx
+++ b/lib/lyx2lyx/lyx2lyx
@@ -63,6 +63,8 @@ Copyright (C) 2011 The LyX Team, José Matos and Dekel Tsur""" 
% LyX.version__
                       help = "list all available formats and supported 
versions")
     parser.add_option("-n", "--try-hard", action="store_true",
                       help = "try hard (ignore any convertion errors)")
+    parser.add_option("-s", "--systemlyxdir", dest= "systemlyxdir",
+                      help= "LyX system directory for conversion from version 
489 or older")
 
     (options, args) = parser.parse_args()
     if args:
diff --git a/lib/lyx2lyx/lyx2lyx_tools.py b/lib/lyx2lyx/lyx2lyx_tools.py
index 1edd1fb..f63f402 100644
--- a/lib/lyx2lyx/lyx2lyx_tools.py
+++ b/lib/lyx2lyx/lyx2lyx_tools.py
@@ -17,7 +17,7 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
 
 '''
-This modules offer several free functions to help with lyx2lyx'ing. 
+This module offers several free functions to help with lyx2lyx'ing. 
 More documentaton is below, but here is a quick guide to what 
 they do. Optional arguments are marked by brackets.
 
@@ -47,18 +47,36 @@ put_cmd_in_ert(arg):
     ert = put_cmd_in_ert(content)
     document.body[i:j+1] = ert
 
+get_ert(lines, i[, verbatim]):
+  Here, lines is a list of lines of LyX material containing an ERT inset,
+  whose content we want to convert to LaTeX. The ERT starts at index i.
+  If the optional (by default: False) bool verbatim is True, the content
+  of the ERT is returned verbatim, that is in LyX syntax (not LaTeX syntax)
+  for the use in verbatim insets.
+
 lyx2latex(document, lines):
-  Here, lines is a list of lines of LyX material we want to convert 
+  Here, lines is a list of lines of LyX material we want to convert
   to LaTeX. We do the best we can and return a string containing
   the translated material.
 
+lyx2verbatim(document, lines):
+  Here, lines is a list of lines of LyX material we want to convert
+  to verbatim material (used in ERT an the like). We do the best we
+  can and return a string containing the translated material.
+
 latex_length(slen):
-    Convert lengths (in LyX form) to their LaTeX representation. Returns 
-    (bool, length), where the bool tells us if it was a percentage, and 
+    Convert lengths (in LyX form) to their LaTeX representation. Returns
+    (bool, length), where the bool tells us if it was a percentage, and
     the length is the LaTeX representation.
 
+convert_info_insets(document, type, func):
+    Applies func to the argument of all info insets matching certain types
+    type : the type to match. This can be a regular expression.
+    func : function from string to string to apply to the "arg" field of
+           the info insets.
 '''
 
+import re
 import string
 from parser_tools import find_token, find_end_of_inset
 from unicode_symbols import unicode_reps
@@ -125,14 +143,14 @@ def put_cmd_in_ert(arg):
     else:
       s = arg
     for rep in unicode_reps:
-      s = s.replace(rep[1], rep[0].replace('\\\\', '\\'))
+      s = s.replace(rep[1], rep[0])
     s = s.replace('\\', "\\backslash\n")
     ret += s.splitlines()
     ret += ["\\end_layout", "", "\\end_inset"]
     return ret
 
 
-def get_ert(lines, i):
+def get_ert(lines, i, verbatim = False):
     'Convert an ERT inset into LaTeX.'
     if not lines[i].startswith("\\begin_inset ERT"):
         return ""
@@ -156,7 +174,10 @@ def get_ert(lines, i):
             while i + 1 < j and lines[i+1] == "":
                 i = i + 1
         elif lines[i] == "\\backslash":
-            ret = ret + "\\"
+            if verbatim:
+                ret = ret + "\n" + lines[i] + "\n"
+            else:
+                ret = ret + "\\"
         else:
             ret = ret + lines[i]
         i = i + 1
@@ -204,6 +225,10 @@ def lyx2latex(document, lines):
                   line = "''"
               else:
                   line = "'"
+      elif line.startswith("\\begin_inset Newline newline"):
+          line = "\\\\ "
+      elif line.startswith("\\noindent"):
+          line = "\\noindent " # we need the space behind the command
       elif line.startswith("\\begin_inset space"):
           line = line[18:].strip()
           if line.startswith("\\hspace"):
@@ -250,7 +275,7 @@ def lyx2latex(document, lines):
 
           # Do the LyX text --> LaTeX conversion
           for rep in unicode_reps:
-            line = line.replace(rep[1], rep[0] + "{}")
+              line = line.replace(rep[1], rep[0])
           line = line.replace(r'\backslash', r'\textbackslash{}')
           line = line.replace(r'\series bold', 
r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
           line = line.replace(r'\shape italic', 
r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
@@ -265,6 +290,15 @@ def lyx2latex(document, lines):
     return content
 
 
+def lyx2verbatim(document, lines):
+    'Convert some LyX stuff into corresponding verbatim stuff, as best we can.'
+
+    content = lyx2latex(document, lines)
+    content = re.sub(r'\\(?!backslash)', r'\n\\backslash\n', content)
+
+    return content
+
+
 def latex_length(slen):
     ''' 
     Convert lengths to their LaTeX representation. Returns (bool, length),
@@ -283,7 +317,7 @@ def latex_length(slen):
     units = {"text%":"\\textwidth", "col%":"\\columnwidth",
              "page%":"\\paperwidth", "line%":"\\linewidth",
              "theight%":"\\textheight", "pheight%":"\\paperheight"}
-    for unit in units.keys():
+    for unit in list(units.keys()):
         i = slen.find(unit)
         if i == -1:
             continue
@@ -319,6 +353,44 @@ def latex_length(slen):
     return (percent, slen)
 
 
+def length_in_bp(length):
+    " Convert a length in LyX format to its value in bp units "
+
+    em_width = 10.0 / 72.27 # assume 10pt font size
+    text_width = 8.27 / 1.7 # assume A4 with default margins
+    # scale factors are taken from Length::inInch()
+    scales = {"bp"       : 1.0,
+              "cc"       : (72.0 / (72.27 / (12.0 * 0.376 * 2.845))),
+              "cm"       : (72.0 / 2.54),
+              "dd"       : (72.0 / (72.27 / (0.376 * 2.845))),
+              "em"       : (72.0 * em_width),
+              "ex"       : (72.0 * em_width * 0.4305),
+              "in"       : 72.0,
+              "mm"       : (72.0 / 25.4),
+              "mu"       : (72.0 * em_width / 18.0),
+              "pc"       : (72.0 / (72.27 / 12.0)),
+              "pt"       : (72.0 / (72.27)),
+              "sp"       : (72.0 / (72.27 * 65536.0)),
+              "text%"    : (72.0 * text_width / 100.0),
+              "col%"     : (72.0 * text_width / 100.0), # assume 1 column
+              "page%"    : (72.0 * text_width * 1.7 / 100.0),
+              "line%"    : (72.0 * text_width / 100.0),
+              "theight%" : (72.0 * text_width * 1.787 / 100.0),
+              "pheight%" : (72.0 * text_width * 2.2 / 100.0)}
+
+    rx = re.compile(r'^\s*([^a-zA-Z%]+)([a-zA-Z%]+)\s*$')
+    m = rx.match(length)
+    if not m:
+        document.warning("Invalid length value: " + length + ".")
+        return 0
+    value = m.group(1)
+    unit = m.group(2)
+    if not unit in scales.keys():
+        document.warning("Unknown length unit: " + unit + ".")
+        return value
+    return "%g" % (float(value) * scales[unit])
+
+
 def revert_flex_inset(lines, name, LaTeXname):
   " Convert flex insets to TeX code "
   i = 0
@@ -436,3 +508,21 @@ def str2bool(s):
   "'true' goes to True, case-insensitively, and we strip whitespace."
   s = s.strip().lower()
   return s == "true"
+
+
+def convert_info_insets(document, type, func):
+    "Convert info insets matching type using func."
+    i = 0
+    type_re = re.compile(r'^type\s+"(%s)"$' % type)
+    arg_re = re.compile(r'^arg\s+"(.*)"$')
+    while True:
+        i = find_token(document.body, "\\begin_inset Info", i)
+        if i == -1:
+            return
+        t = type_re.match(document.body[i + 1])
+        if t:
+            arg = arg_re.match(document.body[i + 2])
+            if arg:
+                new_arg = func(arg.group(1))
+                document.body[i + 2] = 'arg   "%s"' % new_arg
+        i += 3
diff --git a/lib/lyx2lyx/lyx_1_2.py b/lib/lyx2lyx/lyx_1_2.py
index a47fcaf..19b6647 100644
--- a/lib/lyx2lyx/lyx_1_2.py
+++ b/lib/lyx2lyx/lyx_1_2.py
@@ -154,7 +154,7 @@ def remove_oldfloat(document):
         j = find_token(lines, "\\end_float", i+1)
 
         floattype = lines[i].split()[1]
-        if not floats.has_key(floattype):
+        if floattype not in floats:
             document.warning("Error! Unknown float type " + floattype)
             floattype = "fig"
 
@@ -284,7 +284,7 @@ def remove_pextra(document):
 
 def is_empty(lines):
     " Are all the lines empty?"
-    return filter(is_nonempty_line, lines) == []
+    return list(filter(is_nonempty_line, lines)) == []
 
 
 move_rexp =  
re.compile(r"\\(family|series|shape|size|emph|numeric|bar|noun|end_deeper)")
@@ -358,7 +358,7 @@ def remove_oldert(document):
                     tmp.append(line)
 
             if is_empty(tmp):
-                if filter(lambda x:x != "", tmp) != []:
+                if [x for x in tmp if x != ""] != []:
                     if new == []:
                         # This is not necessary, but we want the output to be
                         # as similar as posible to the lyx format
diff --git a/lib/lyx2lyx/lyx_1_4.py b/lib/lyx2lyx/lyx_1_4.py
index 9fb583f..c1a4591 100644
--- a/lib/lyx2lyx/lyx_1_4.py
+++ b/lib/lyx2lyx/lyx_1_4.py
@@ -1495,7 +1495,7 @@ def convert_len(len, special):
         len = '%f\\' % len2value(len) + special
 
     # Convert LyX units to LaTeX units
-    for unit in units.keys():
+    for unit in list(units.keys()):
         if len.find(unit) != -1:
             len = '%f' % (len2value(len) / 100) + units[unit]
             break
@@ -1571,7 +1571,7 @@ def convert_frameless_box(document):
                   'inner_pos':1, 'use_parbox':'0', 'width':'100col%',
                   'special':'none', 'height':'1in',
                   'height_special':'totalheight', 'collapsed':'false'}
-        for key in params.keys():
+        for key in list(params.keys()):
             value = get_value(document.body, key, i, j).replace('"', '')
             if value != "":
                 if key == 'position':
diff --git a/lib/lyx2lyx/lyx_1_5.py b/lib/lyx2lyx/lyx_1_5.py
index 96d9589..97adec9 100644
--- a/lib/lyx2lyx/lyx_1_5.py
+++ b/lib/lyx2lyx/lyx_1_5.py
@@ -26,6 +26,15 @@ import sys, os
 from parser_tools import find_re, find_token, find_token_backwards, 
find_token_exact, find_tokens, find_end_of, get_value, find_beginning_of, 
find_nonempty_line
 from LyX import get_encoding
 
+# Provide support for both python 2 and 3
+PY2 = sys.version_info[0] == 2
+if not PY2:
+    text_type = str
+    unichr = chr
+else:
+    text_type = unicode
+    unichr = unichr
+# End of code to support for both python 2 and 3
 
 ####################################################################
 # Private helper functions
@@ -93,7 +102,7 @@ def convert_font_settings(document):
     if font_scheme == '':
         document.warning("Malformed LyX document: Empty `\\fontscheme'.")
         font_scheme = 'default'
-    if not font_scheme in roman_fonts.keys():
+    if not font_scheme in list(roman_fonts.keys()):
         document.warning("Malformed LyX document: Unknown `\\fontscheme' 
`%s'." % font_scheme)
         font_scheme = 'default'
     document.header[i:i+1] = ['\\font_roman %s' % roman_fonts[font_scheme],
@@ -163,7 +172,7 @@ def revert_font_settings(document):
         del document.header[i]
     if font_tt_scale != '100':
         document.warning("Conversion of '\\font_tt_scale' not yet 
implemented.")
-    for font_scheme in roman_fonts.keys():
+    for font_scheme in list(roman_fonts.keys()):
         if (roman_fonts[font_scheme] == fonts['roman'] and
             sans_fonts[font_scheme] == fonts['sans'] and
             typewriter_fonts[font_scheme] == fonts['typewriter']):
@@ -334,6 +343,7 @@ def revert_utf8(document):
     convert_multiencoding(document, False)
 
 
+# FIXME: Use the version in unicode_symbols.py which has some bug fixes
 def read_unicodesymbols():
     " Read the unicodesymbols list of unicode characters and corresponding 
commands."
     pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
@@ -376,7 +386,7 @@ def revert_unicode_line(document, i, insets, spec_chars, 
replacement_character =
             last_char = character
         except:
             # Try to replace with ERT/math inset
-            if spec_chars.has_key(character):
+            if character in spec_chars:
                 command = spec_chars[character][0] # the command to replace 
unicode
                 flag1 = spec_chars[character][1]
                 flag2 = spec_chars[character][2]
@@ -1211,7 +1221,7 @@ def revert_accent(document):
         try:
             document.body[i] = normalize("NFD", document.body[i])
         except TypeError:
-            document.body[i] = normalize("NFD", unicode(document.body[i], 
'utf-8'))
+            document.body[i] = normalize("NFD", text_type(document.body[i], 
'utf-8'))
 
     # Replace accented characters with InsetLaTeXAccent
     # Do not convert characters that can be represented in the chosen
@@ -1346,15 +1356,15 @@ def normalize_font_whitespace(document, 
char_properties):
             # a new paragraph resets all font changes
             changes.clear()
             # also reset the default language to be the paragraph's language
-            if "\\lang" in char_properties.keys():
+            if "\\lang" in list(char_properties.keys()):
                 char_properties["\\lang"] = \
                     get_paragraph_language(document, i + 1)
 
-        elif len(words) > 1 and words[0] in char_properties.keys():
+        elif len(words) > 1 and words[0] in list(char_properties.keys()):
             # we have a font change
             if char_properties[words[0]] == words[1]:
                 # property gets reset
-                if words[0] in changes.keys():
+                if words[0] in list(changes.keys()):
                     del changes[words[0]]
                 defaultproperty = True
             else:
@@ -1372,11 +1382,11 @@ def normalize_font_whitespace(document, 
char_properties):
                 lines[i-1] = lines[i-1][:-1]
                 # a space before the font change
                 added_lines = [" "]
-                for k in changes.keys():
+                for k in list(changes.keys()):
                     # exclude property k because that is already in lines[i]
                     if k != words[0]:
                         added_lines[1:1] = ["%s %s" % (k, changes[k])]
-                for k in changes.keys():
+                for k in list(changes.keys()):
                     # exclude property k because that must be added below 
anyway
                     if k != words[0]:
                         added_lines[0:0] = ["%s %s" % (k, char_properties[k])]
@@ -1400,11 +1410,11 @@ def normalize_font_whitespace(document, 
char_properties):
                         continue
                 lines[i+1] = lines[i+1][1:]
                 added_lines = [" "]
-                for k in changes.keys():
+                for k in list(changes.keys()):
                     # exclude property k because that is already in lines[i]
                     if k != words[0]:
                         added_lines[1:1] = ["%s %s" % (k, changes[k])]
-                for k in changes.keys():
+                for k in list(changes.keys()):
                     # exclude property k because that must be added below 
anyway
                     if k != words[0]:
                         added_lines[0:0] = ["%s %s" % (k, char_properties[k])]
diff --git a/lib/lyx2lyx/lyx_1_6.py b/lib/lyx2lyx/lyx_1_6.py
index 2d0964c..2f8ebd2 100644
--- a/lib/lyx2lyx/lyx_1_6.py
+++ b/lib/lyx2lyx/lyx_1_6.py
@@ -94,7 +94,7 @@ def convert_len(len):
              "theight%":"\\backslash\ntextheight", 
"pheight%":"\\backslash\npageheight"}
 
     # Convert LyX units to LaTeX units
-    for unit in units.keys():
+    for unit in list(units.keys()):
         if len.find(unit) != -1:
             len = '%f' % (len2value(len) / 100)
             len = len.strip('0') + units[unit]
@@ -145,6 +145,7 @@ def set_option(document, m, option, value):
     return l
 
 
+# FIXME: Use the version in unicode_symbols.py which has some bug fixes
 def read_unicodesymbols():
     " Read the unicodesymbols list of unicode characters and corresponding 
commands."
     pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
@@ -1765,7 +1766,7 @@ def convert_module_names(document):
     return
   newmodlist = []
   for mod in modlist:
-    if modulemap.has_key(mod):
+    if mod in modulemap:
       newmodlist.append(modulemap[mod])
     else:
       document.warning("Can't find module %s in the module map!" % mod)
diff --git a/lib/lyx2lyx/lyx_2_0.py b/lib/lyx2lyx/lyx_2_0.py
index 7914cc4..1f10154 100644
--- a/lib/lyx2lyx/lyx_2_0.py
+++ b/lib/lyx2lyx/lyx_2_0.py
@@ -89,10 +89,7 @@ def revert_tabularvalign(document):
       if p != -1:
           q = document.body[fline].find("tabularvalignment")
           if q != -1:
-              # FIXME
-              # This seems wrong: It removes everything after 
-              # tabularvalignment, too.
-              document.body[fline] = document.body[fline][:q - 1] + '>'
+              document.body[fline] = re.sub(r' tabularvalignment=\"[a-z]+\"', 
"", document.body[fline])
           i += 1
           continue
 
@@ -108,16 +105,13 @@ def revert_tabularvalign(document):
       # delete tabularvalignment
       q = document.body[fline].find("tabularvalignment")
       if q != -1:
-          # FIXME
-          # This seems wrong: It removes everything after 
-          # tabularvalignment, too.
-          document.body[fline] = document.body[fline][:q - 1] + '>'
+          document.body[fline] = re.sub(r' tabularvalignment=\"[a-z]+\"', "", 
document.body[fline])
 
       # don't add a box when centered
       if tabularvalignment == 'c':
           i = end
           continue
-      subst = ['\\end_layout', '\\end_inset']
+      subst = ['\\end_inset', '\\end_layout']
       document.body[end:end] = subst # just inserts those lines
       subst = ['\\begin_inset Box Frameless',
           'position "' + tabularvalignment +'"',
@@ -563,7 +557,6 @@ def revert_nomencl_cwidth(document):
       j = find_end_of_inset(document.body, i)
       l = find_token(document.body, "width", i, j)
       if l == -1:
-        document.warning("Can't find width option for nomencl_print!")
         i = j
         continue
       width = get_quoted_value(document.body, "width", i, j)
@@ -1585,10 +1578,13 @@ def convert_use_makebox(document):
 
 def revert_IEEEtran(document):
   " Convert IEEEtran layouts and styles to TeX code "
+
   if document.textclass != "IEEEtran":
     return
+
   revert_flex_inset(document.body, "IEEE membership", "\\IEEEmembership")
   revert_flex_inset(document.body, "Lowercase", "\\MakeLowercase")
+
   layouts = ("Special Paper Notice", "After Title Text", "Publication ID",
              "Page headings", "Biography without photo")
   latexcmd = {"Special Paper Notice": "\\IEEEspecialpapernotice",
@@ -1596,6 +1592,7 @@ def revert_IEEEtran(document):
               "Publication ID":       "\\IEEEpubid"}
   obsoletedby = {"Page headings":            "MarkBoth",
                  "Biography without photo":  "BiographyNoPhoto"}
+
   for layout in layouts:
     i = 0
     while True:
@@ -1607,7 +1604,7 @@ def revert_IEEEtran(document):
           document.warning("Malformed LyX document: Can't find end of " + 
layout + " layout.")
           i += 1
           continue
-        if layout in obsoletedby:
+        if layout in list(obsoletedby.keys()):
           document.body[i] = "\\begin_layout " + obsoletedby[layout]
           i = j
           continue
@@ -2394,13 +2391,12 @@ def revert_script(document):
 
 def convert_use_xetex(document):
     " convert \\use_xetex to \\use_non_tex_fonts "
-    i = 0
     i = find_token(document.header, "\\use_xetex", 0)
     if i == -1:
-        return
-    
-    val = get_value(document.header, "\\use_xetex", 0)
-    document.header[i] = "\\use_non_tex_fonts " + val
+        document.header.insert(-1, "\\use_non_tex_fonts 0")
+    else:
+        val = get_value(document.header, "\\use_xetex", 0)
+        document.header[i] = "\\use_non_tex_fonts " + val
 
 
 def revert_use_xetex(document):
diff --git a/lib/lyx2lyx/lyx_2_1.py b/lib/lyx2lyx/lyx_2_1.py
index f5b3aee..fe5f9d6 100644
--- a/lib/lyx2lyx/lyx_2_1.py
+++ b/lib/lyx2lyx/lyx_2_1.py
@@ -58,7 +58,7 @@ def revert_Argument_to_TeX_brace(document, line, endline, n, 
nmax, environment,
     Reverts an InsetArgument to TeX-code
     usage:
     revert_Argument_to_TeX_brace(document, LineOfBegin, LineOfEnd, 
StartArgument, EndArgument, isEnvironment, isOpt)
-    LineOfBegin is the line  of the \begin_layout or \begin_inset statement
+    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
@@ -111,7 +111,7 @@ def convert_TeX_brace_to_Argument(document, line, n, nmax, 
inset, environment, o
     - { and } surround a mandatory argument of an environment
     usage:
     convert_TeX_brace_to_Argument(document, LineOfBeginLayout/Inset, 
StartArgument, EndArgument, isInset, isEnvironment, isOpt)
-    LineOfBeginLayout/Inset is the line  of the \begin_layout or \begin_inset 
statement
+    LineOfBeginLayout/Inset is the line  of the \\begin_layout or 
\\begin_inset statement
     StartArgument is the number of the first ERT that needs to be converted
     EndArgument is the number of the last ERT that needs to be converted
     isInset must be true, if braces inside an InsetLayout needs to be converted
@@ -181,7 +181,7 @@ def convert_TeX_brace_to_Argument(document, line, n, nmax, 
inset, environment, o
             else:
               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:
+            if beginBrance != -1 and (beginBrace == endBrace + 11 or 
beginBrace == endBrace + 12):
               end = find_token(document.body, "\\end_inset", beginBrace)
               document.body[lineERT : end + 1] = ["\\end_layout", "", 
"\\end_inset"]
               if loop == 1:
@@ -398,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]
 
 
@@ -413,7 +413,7 @@ 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]
 
 
@@ -814,30 +814,38 @@ def revert_cancel(document):
     revert_use_package(document, "cancel", cancel_commands, False)
 
 
-def revert_verbatim(document):
-    " Revert verbatim einvironments completely to TeX-code. "
+def revert_verbatim(document, starred = False):
+    " Revert verbatim environments completely to TeX-code. "
     i = 0
     consecutive = False
-    subst_end = ['\end_layout', '', '\\begin_layout Plain Layout',
-                '\end_layout', '',
+
+    layout_name = "Verbatim"
+    latex_name  = "verbatim"
+    if starred:
+        layout_name = "Verbatim*"
+        latex_name  = "verbatim*"
+
+    subst_end = ['\\end_layout', '', '\\begin_layout Plain Layout',
+                 '\\end_layout', '',
                  '\\begin_layout Plain Layout', '', '',
                  '\\backslash', '',
-                 'end{verbatim}',
+                 'end{%s}' % (latex_name),
                  '\\end_layout', '', '\\end_inset',
                  '', '', '\\end_layout']
     subst_begin = ['\\begin_layout Standard', '\\noindent',
                    '\\begin_inset ERT', 'status open', '',
                    '\\begin_layout Plain Layout', '', '', '\\backslash',
-                   'begin{verbatim}',
+                   'begin{%s}' % (latex_name),
                    '\\end_layout', '', '\\begin_layout Plain Layout', '']
 
     while 1:
-        i = find_token(document.body, "\\begin_layout Verbatim", i)
+        i = find_token(document.body, "\\begin_layout %s" % (layout_name), 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 
Verbatim layout")
+            document.warning("Malformed LyX document: Can't find end of %s 
layout" \
+              % (layout_name))
             i += 1
             continue
         # delete all line breaks insets (there are no other insets)
@@ -850,24 +858,29 @@ def revert_verbatim(document):
                     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']
+            document.body[n:n+1] = ['\\end_layout', '', '\\begin_layout Plain 
Layout']
             l += 1
             # we deleted a line, so the end of the inset moved forward.
+            # FIXME But we also added some lines, didn't we? I think this
+            # should be j += 1.
             j -= 1
         # consecutive verbatim environments need to be connected
-        k = find_token(document.body, "\\begin_layout Verbatim", j)
+        k = find_token(document.body, "\\begin_layout %s" % (layout_name), j)
         if k == j + 2 and consecutive == False:
             consecutive = True
-            document.body[j:j+1] = ['\end_layout', '', '\\begin_layout Plain 
Layout']
+            document.body[j:j+1] = ['\\end_layout', '', '\\begin_layout Plain 
Layout']
             document.body[i:i+1] = subst_begin
             continue
         if k == j + 2 and consecutive == True:
-            document.body[j:j+1] = ['\end_layout', '', '\\begin_layout Plain 
Layout']
+            document.body[j:j+1] = ['\\end_layout', '', '\\begin_layout Plain 
Layout']
             del(document.body[i:i+1])
             continue
         if k != j + 2 and consecutive == True:
             document.body[j:j+1] = subst_end
             # the next paragraph must not be indented
+            # FIXME This seems to be causing problems, because of the
+            # hardcoded use of 19. We should figure out exactly where
+            # this needs to go by searching for the right tag.
             document.body[j+19:j+19] = ['\\noindent']
             del(document.body[i:i+1])
             consecutive = False
@@ -875,6 +888,9 @@ def revert_verbatim(document):
         else:
             document.body[j:j+1] = subst_end
             # the next paragraph must not be indented
+            # FIXME This seems to be causing problems, because of the
+            # hardcoded use of 19. We should figure out exactly where
+            # this needs to go by searching for the right tag.
             document.body[j+19:j+19] = ['\\noindent']
             document.body[i:i+1] = subst_begin
 
@@ -1227,7 +1243,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)
@@ -1391,7 +1407,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:
@@ -1412,7 +1428,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]
@@ -1424,6 +1440,10 @@ def revert_mdnomath(document):
                 document.header[i] = "\\font_roman %s" % mathdesign_dict[val]
 
 
+def convert_mathfonts(document):
+    document.header.insert(-1, "\\font_math auto")
+
+
 def convert_mdnomath(document):
     " Change mathdesign font name " 
 
@@ -1437,7 +1457,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]
 
 
@@ -1454,7 +1474,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"
 
@@ -1669,46 +1689,49 @@ def revert_latexargs(document):
 
 
 def revert_IEEEtran(document):
-  '''
-  Reverts InsetArgument of
-  Page headings
-  Biography
-  Biography without photo
-  to TeX-code
-  '''
-  if document.textclass == "IEEEtran":
+    '''
+    Reverts InsetArgument of
+    Page headings
+    Biography
+    Biography without photo
+    to TeX-code
+    '''
+    if document.textclass != "IEEEtran":
+        return
+
+    layouts = {"Page headings": False,
+               "Biography without photo": True}
+
+    for layout in list(layouts.keys()):
+        i = 0
+        while True:
+            i = find_token(document.body, '\\begin_layout ' + layout, i)
+            if i == -1:
+                break
+            revert_Argument_to_TeX_brace(document, i, 0, 1, 1, 
layouts[layout], False)
+            i += 1
+
     i = 0
-    i2 = 0
-    j = 0
-    k = 0
     while True:
-      if i != -1:
-        i = find_token(document.body, "\\begin_layout Page headings", i)
-      if i != -1:
+        i = find_token(document.body, '\\begin_inset Flex Paragraph Start', i)
+        if i == -1:
+            break
         revert_Argument_to_TeX_brace(document, i, 0, 1, 1, False, False)
         i += 1
-      if i2 != -1:
-        i2 = find_token(document.body, "\\begin_inset Flex Paragraph Start", 
i2)
-      if i2 != -1:
-        revert_Argument_to_TeX_brace(document, i2, 0, 1, 1, False, False)
-        i2 = i2 + 1
-      if j != -1:
-        j = find_token(document.body, "\\begin_layout Biography without 
photo", j)
-      if j != -1:
-        revert_Argument_to_TeX_brace(document, j, 0, 1, 1, True, False)
-        j += 1
-      if k != -1:
-        k = find_token(document.body, "\\begin_layout Biography", k)
-        kA = find_token(document.body, "\\begin_layout Biography without 
photo", k)
-        if k == kA and k != -1:
-          k += 1
-          continue
-      if k != -1:
+
+    i = 0
+    while True:
+        i = find_token_exact(document.body, "\\begin_layout Biography", i)
+        if i == -1:
+                break
+
+        if document.body[i] == "\\begin_layout Biography without photo":
+            i += 1
+            continue
+
         # start with the second argument, therefore 2
-        revert_Argument_to_TeX_brace(document, k, 0, 2, 2, True, False)
-        k += 1
-      if i == -1 and i2 == -1 and j == -1 and k == -1:
-        return
+        revert_Argument_to_TeX_brace(document, i, 0, 2, 2, True, False)
+        i += 1
 
 
 def revert_IEEEtran_2(document):
@@ -1728,41 +1751,41 @@ def revert_IEEEtran_2(document):
 
 
 def convert_IEEEtran(document):
-  '''
-  Converts ERT of
-  Page headings
-  Biography
-  Biography without photo
-  to InsetArgument
-  '''
-  if document.textclass == "IEEEtran":
+    '''
+    Converts ERT of
+    Page headings
+    Biography
+    Biography without photo
+    to InsetArgument
+    '''
+    if document.textclass != "IEEEtran":
+        return
+
+    layouts = {"Page headings": False,
+               "Biography without photo": True}
+
+    for layout in list(layouts.keys()):
+        i = 0
+        while True:
+            i = find_token(document.body, '\\begin_layout ' + layout, i)
+            if i == -1:
+                break
+            convert_TeX_brace_to_Argument(document, i, 1, 1, False, 
layouts[layout], False)
+            i += 1
+
     i = 0
-    j = 0
-    k = 0
     while True:
-      if i != -1:
-        i = find_token(document.body, "\\begin_layout Page headings", i)
-      if i != -1:
-        convert_TeX_brace_to_Argument(document, i, 1, 1, False, False, False)
-        i += 1
-      if j != -1:
-        j = find_token(document.body, "\\begin_layout Biography without 
photo", j)
-      if j != -1:
-        convert_TeX_brace_to_Argument(document, j, 1, 1, False, True, False)
-        j += 1
-      if k != -1:
-        # assure that we don't handle Biography Biography without photo
-        k = find_token(document.body, "\\begin_layout Biography", k)
-        kA = find_token(document.body, "\\begin_layout Biography without 
photo", k - 1)
-      if k == kA and k != -1:
-        k += 1
-        continue
-      if k != -1:
+        i = find_token_exact(document.body, "\\begin_layout Biography", i)
+        if i == -1:
+                break
+
+        if document.body[i] == "\\begin_layout Biography without photo":
+            i += 1
+            continue
+
         # the argument we want to convert is the second one
-        convert_TeX_brace_to_Argument(document, k, 2, 2, False, True, False)
-        k += 1
-      if i == -1 and j == -1 and k == -1:
-        return
+        convert_TeX_brace_to_Argument(document, i, 2, 2, False, True, False)
+        i += 1
 
 
 def revert_AASTeX(document):
@@ -3630,7 +3653,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'.")
@@ -3666,7 +3689,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
         
@@ -3847,7 +3870,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
@@ -3963,7 +3986,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)
@@ -4004,7 +4027,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)
@@ -4810,7 +4833,7 @@ convert = [
            [437, []],
            [438, []],
            [439, []],
-           [440, []],
+           [440, [convert_mathfonts]],
            [441, [convert_mdnomath]],
            [442, []],
            [443, []],
diff --git a/lib/lyx2lyx/parser_tools.py b/lib/lyx2lyx/parser_tools.py
index 2b6ae05..85e2b6a 100644
--- a/lib/lyx2lyx/parser_tools.py
+++ b/lib/lyx2lyx/parser_tools.py
@@ -56,9 +56,9 @@ find_re(lines, rexp, start[, end]):
 get_value(lines, token, start[, end[, default]):
   Similar to find_token, but it returns what follows the 
   token on the found line. Example:
-    get_value(document.header, "\use_xetex", 0)
+    get_value(document.header, "\\use_xetex", 0)
   will find a line like:
-    \use_xetex true
+    \\use_xetex true
   and, in that case, return "true". (Note that whitespace
   is stripped.) The final argument, default, defaults to "", 
   and is what is returned if we do not find anything. So you
@@ -80,10 +80,10 @@ del_token(lines, token, start[, end]):
 
 find_beginning_of(lines, i, start_token, end_token):
   Here, start_token and end_token are meant to be a matching 
-  pair, like "\begin_layout" and "\end_layout". We look for 
+  pair, like "\\begin_layout" and "\\end_layout". We look for 
   the start_token that pairs with the end_token that occurs
   on or after line i. Returns -1 if not found.
-  So, in the layout case, this would find the \begin_layout 
+  So, in the layout case, this would find the \\begin_layout 
   for the layout line i is in. 
   Example:
     ec = find_token(document.body, "</cell", i)
@@ -187,7 +187,7 @@ def find_token(lines, token, start, end = 0, ignorews = 
False):
     if end == 0 or end > len(lines):
         end = len(lines)
     m = len(token)
-    for i in xrange(start, end):
+    for i in range(start, end):
         if ignorews:
             x = lines[i].split()
             y = token.split()
@@ -215,7 +215,7 @@ def find_tokens(lines, tokens, start, end = 0, ignorews = 
False):
     if end == 0 or end > len(lines):
         end = len(lines)
 
-    for i in xrange(start, end):
+    for i in range(start, end):
         for token in tokens:
             if ignorews:
                 x = lines[i].split()
@@ -244,7 +244,7 @@ def find_re(lines, rexp, start, end = 0):
 
     if end == 0 or end > len(lines):
         end = len(lines)
-    for i in xrange(start, end):
+    for i in range(start, end):
         if rexp.match(lines[i]):
                 return i
     return -1
@@ -258,7 +258,7 @@ def find_token_backwards(lines, token, start):
 
     Return -1 on failure."""
     m = len(token)
-    for i in xrange(start, -1, -1):
+    for i in range(start, -1, -1):
         line = lines[i]
         if line[:m] == token:
             return i
@@ -272,7 +272,7 @@ def find_tokens_backwards(lines, tokens, start):
     element, in lines[end, start].
 
     Return -1 on failure."""
-    for i in xrange(start, -1, -1):
+    for i in range(start, -1, -1):
         line = lines[i]
         for token in tokens:
             if line[:len(token)] == token:
@@ -381,7 +381,7 @@ def find_end_of(lines, i, start_token, end_token):
 def find_nonempty_line(lines, start, end = 0):
     if end == 0:
         end = len(lines)
-    for i in xrange(start, end):
+    for i in range(start, end):
         if is_nonempty_line(lines[i]):
             return i
     return -1
@@ -425,7 +425,7 @@ def is_in_inset(lines, i, inset):
 def get_containing_inset(lines, i):
   ''' 
   Finds out what kind of inset line i is within. Returns a 
-  list containing (i) what follows \begin_inset on the line 
+  list containing (i) what follows \begin_inset on the line
   on which the inset begins, plus the starting and ending line.
   Returns False on any kind of error or if it isn't in an inset.
   '''
@@ -452,7 +452,7 @@ def get_containing_inset(lines, i):
 def get_containing_layout(lines, i):
   ''' 
   Finds out what kind of layout line i is within. Returns a 
-  list containing what follows \begin_layout on the line 
+  list containing what follows \begin_layout on the line
   on which the layout begins, plus the starting and ending line
   and the start of the paragraph (after all params). I.e, returns:
     (layoutname, layoutstart, layoutend, startofcontent)
@@ -487,7 +487,7 @@ def get_containing_layout(lines, i):
 
 
 def count_pars_in_inset(lines, i):
-  ''' 
+  '''
   Counts the paragraphs within this inset
   '''
   ins = get_containing_inset(lines, i)
@@ -498,12 +498,12 @@ def count_pars_in_inset(lines, i):
       m = re.match(r'\\begin_layout (.*)', lines[j])
       if m and get_containing_inset(lines, j)[0] == ins[0]:
           pars += 1
-  
+
   return pars
 
 
 def find_end_of_sequence(lines, i):
-  ''' 
+  '''
   Returns the end of a sequence of identical layouts.
   '''
   lay = get_containing_layout(lines, i)
diff --git a/lib/lyx2lyx/test_parser_tools.py b/lib/lyx2lyx/test_parser_tools.py
index a8ef944..7e34947 100644
--- a/lib/lyx2lyx/test_parser_tools.py
+++ b/lib/lyx2lyx/test_parser_tools.py
@@ -78,8 +78,8 @@ class TestParserTools(unittest.TestCase):
     def test_find_token(self):
         self.assertEquals(find_token(lines, '\\emph', 0), 7)
         self.assertEquals(find_token(lines, '\\emph', 0, 5), -1)
-        self.assertEquals(find_token(lines, '\\emp', 0, exact = True), -1)
-        self.assertEquals(find_token(lines, '\\emp', 0, exact = False), 7)
+        self.assertEquals(find_token(lines, '\\emp', 0, 0, True), -1)
+        self.assertEquals(find_token(lines, '\\emp', 0, 0, False), 7)
         self.assertEquals(find_token(lines, 'emph', 0), -1)
 
 
diff --git a/lib/lyx2lyx/unicode_symbols.py b/lib/lyx2lyx/unicode_symbols.py
index 9df65e8..f24f3a9 100644
--- a/lib/lyx2lyx/unicode_symbols.py
+++ b/lib/lyx2lyx/unicode_symbols.py
@@ -20,35 +20,47 @@
 
 import sys, os, re
 
+# Provide support for both python 2 and 3
+PY2 = sys.version_info[0] == 2
+if not PY2:
+    unichr = chr
+# End of code to support for both python 2 and 3
+
 def read_unicodesymbols():
     " Read the unicodesymbols list of unicode characters and corresponding 
commands."
     pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
     fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
     spec_chars = []
-    # Two backslashes, followed by some non-word character, and then a 
character
+    # A backslash, followed by some non-word character, and then a character
     # in brackets. The idea is to check for constructs like: \"{u}, which is 
how
     # they are written in the unicodesymbols file; but they can also be written
     # as: \"u or even \" u.
-    r = re.compile(r'\\\\(\W)\{(\w)\}')
+    # The two backslashes in the string literal are needed to specify a literal
+    # backslash in the regex. Without r prefix, these would be four 
backslashes.
+    r = re.compile(r'\\(\W)\{(\w)\}')
     for line in fp.readlines():
         if line[0] != '#' and line.strip() != "":
+            # Note: backslashes in the string literals with r prefix are not 
escaped,
+            #       so one backslash in the source file equals one backslash 
in memory.
+            #       Without r prefix backslahses are escaped, so two 
backslashes in the
+            #       source file equal one backslash in memory.
             line=line.replace(' "',' ') # remove all quotation marks with 
spaces before
             line=line.replace('" ',' ') # remove all quotation marks with 
spaces after
-            line=line.replace(r'\"','"') # replace \" by " (for characters 
with diaeresis)
+            line=line.replace(r'\"','"') # unescape "
+            line=line.replace(r'\\','\\') # unescape \
             try:
                 [ucs4,command,dead] = line.split(None,2)
                 if command[0:1] != "\\":
                     continue
+                if (line.find("notermination=text") < 0 and
+                    line.find("notermination=both") < 0 and command[-1] != 
"}"):
+                    command = command + "{}"
                 spec_chars.append([command, unichr(eval(ucs4))])
             except:
                 continue
             m = r.match(command)
             if m != None:
-                command = "\\\\"
-                # If the character is a double-quote, then we need to escape 
it, too,
-                # since it is done that way in the LyX file.
-                if m.group(1) == "\"":
-                    command += "\\"
+                command = "\\"
                 commandbl = command
                 command += m.group(1) + m.group(2)
                 commandbl += m.group(1) + ' ' + m.group(2)

Reply via email to