]> git.lyx.org Git - lyx.git/blobdiff - lib/lyx2lyx/lyx_2_2.py
Added Adobe Source Pro fonts to lyx-GUI
[lyx.git] / lib / lyx2lyx / lyx_2_2.py
index ced6482e1fac5838f941311fccbbae740737dc64..d8d9ab65b55d00b5afa586e76771aa5a6af99668 100644 (file)
@@ -24,25 +24,21 @@ import sys, os
 
 # Uncomment only what you need to import, please.
 
-#from parser_tools import find_token, find_end_of, find_tokens, \
-#  find_token_exact, find_end_of_inset, find_end_of_layout, \
-#  find_token_backwards, is_in_inset, get_value, get_quoted_value, \
-#  del_token, check_token, get_option_value
+from lyx2lyx_tools import (add_to_preamble, put_cmd_in_ert, get_ert,
+    lyx2latex, lyx2verbatim, length_in_bp, convert_info_insets, insert_document_option)
 
-from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, get_ert, lyx2latex, \
-  lyx2verbatim, length_in_bp, convert_info_insets
-#  insert_to_preamble, latex_length, revert_flex_inset, \
-#  revert_font_attrs, hex2ratio, str2bool
+from parser_tools import (check_token, del_complete_lines,
+    find_end_of_inset, find_end_of_layout, find_nonempty_line, find_re,
+    find_substring, find_token, find_token_backwards, get_containing_layout,
+    get_containing_inset, get_quoted_value, get_value, is_in_inset,
+    get_bool_value, set_bool_value)
 
-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)
@@ -53,7 +49,7 @@ def revert_Argument_to_TeX_brace(document, line, endline, n, nmax, environment,
     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:
@@ -186,6 +182,13 @@ def convert_separator(document):
 
         j = find_token_backwards(document.body, "\\end_layout", i-1)
         if j != -1:
+            # Very old LyX files do not have Plain Layout in insets (but Standard).
+            # So we additionally check here if there is no inset boundary
+            # between the previous layout and this one.
+            n = find_token(document.body, "\\end_inset", j, lay[1])
+            if n != -1:
+                i = i + 1
+                continue
             lay = get_containing_layout(document.body, j-1)
             if lay != False and lay[0] == "Standard" \
                and find_token(document.body, "\\align", lay[1], lay[2]) == -1 \
@@ -616,95 +619,101 @@ def convert_dashes(document):
         return
 
     i = 0
-    while i < len(document.body):
-        words = document.body[i].split()
-        if (len(words) > 1 and words[0] == "\\begin_inset"
-            and (words[1] in ["CommandInset", "ERT", "External", "Formula",
-                              "FormulaMacro", "Graphics", "IPA", "listings"]
-                 or ' '.join(words[1:]) == "Flex Code")):
-            # must not replace anything in insets that store LaTeX contents in .lyx files
-            # (math and command insets without overridden read() and write() methods
-            # filtering out IPA makes Text::readParToken() more simple
-            # skip ERT as well since it is not needed there
-            # Flex Code is logical markup, typically rendered as typewriter
-            j = find_end_of_inset(document.body, i)
-            if j == -1:
-                document.warning("Malformed LyX document: Can't find end of " + words[1] + " inset at line " + str(i))
-                i += 1
-            else:
-                i = j
+    while True:
+        i = find_substring(document.body, "--", i+1)
+        if i == -1:
+            break
+        line = document.body[i]
+        # skip label width string (bug 10243):
+        if line.startswith("\\labelwidthstring"):
             continue
-        if document.body[i] == "\\begin_layout LyX-Code":
-            j = find_end_of_layout(document.body, i)
-            if j == -1:
-                document.warning("Malformed LyX document: "
-                    "Can't find end of %s layout at line %d" % (words[1],i))
-                i += 1
-            else:
-                i = j
+        # Do not touch hyphens in some insets:
+        try:
+            value, start, end = get_containing_inset(document.body, i)
+        except TypeError:
+            # False means no (or malformed) containing inset
+            value, start, end = "no inset", -1, -1
+        # We must not replace anything in insets that store LaTeX contents in .lyx files
+        # (math and command insets without overridden read() and write() methods.
+        # Filtering out IPA and ERT makes Text::readParToken() more simple,
+        # Flex Code is logical markup, typically rendered as typewriter
+        if (value.split()[0] in ["CommandInset", "ERT", "External", "Formula",
+                                 "FormulaMacro", "Graphics", "IPA", "listings"]
+            or value in ["Flex Code", "Flex URL"]):
+            i = end
             continue
-
-        if len(words) > 0 and words[0] in ["\\leftindent", "\\paragraph_spacing", "\\align", "\\labelwidthstring"]:
-            # skip paragraph parameters (bug 10243)
-            i += 1
+        try:
+            layout, start, end, j = get_containing_layout(document.body, i)
+        except TypeError: # no (or malformed) containing layout
+            document.warning("Malformed LyX document: "
+                             "Can't find layout at line %d" % i)
             continue
-        while True:
-            j = document.body[i].find("--")
-            if j == -1:
-                break
-            front = document.body[i][:j]
-            back = document.body[i][j+2:]
-            # We can have an arbitrary number of consecutive hyphens.
-            # These must be split into the corresponding number of two and three hyphens
-            # We must match what LaTeX does: First try emdash, then endash, then single hyphen
-            if back.find("-") == 0:
-                back = back[1:]
-                if len(back) > 0:
-                    document.body.insert(i+1, back)
-                document.body[i] = front + "\\threehyphens"
-            else:
-                if len(back) > 0:
-                    document.body.insert(i+1, back)
-                document.body[i] = front + "\\twohyphens"
-        i += 1
+        if layout == "LyX-Code":
+            i = end
+            continue
+        # We can have an arbitrary number of consecutive hyphens.
+        # Replace as LaTeX does: First try emdash, then endash
+        line = line.replace("---", "\\threehyphens\n")
+        line = line.replace("--", "\\twohyphens\n")
+        document.body[i:i+1] = line.split('\n')
+
+    # remove ligature breaks between dashes
+    i = 0
+    while True:
+        i = find_substring(document.body,
+                           r"-\SpecialChar \textcompwordmark{}", i+1)
+        if i == -1:
+            break
+        if document.body[i+1].startswith("-"):
+            document.body[i] = document.body[i].replace(
+                r"\SpecialChar \textcompwordmark{}", document.body.pop(i+1))
 
 
 def revert_dashes(document):
-    "convert \\twohyphens and \\threehyphens to -- and ---"
-
-    # eventually remove preamble code from 2.3->2.2 conversion:
-    for i, line in enumerate(document.preamble):
-        if i > 1 and line == r'\renewcommand{\textemdash}{---}':
-            if (document.preamble[i-1] == r'\renewcommand{\textendash}{--}'
-                and document.preamble[i-2] == '% Added by lyx2lyx'):
-                del document.preamble[i-2:i+1]
+    """
+    Remove preamble code from 2.3->2.2 conversion.
+    Prevent ligatures of existing --- and --.
+    Revert \\twohyphens and \\threehyphens to -- and ---.
+    """
+    del_complete_lines(document.preamble,
+                       ['% Added by lyx2lyx',
+                        r'\renewcommand{\textendash}{--}',
+                        r'\renewcommand{\textemdash}{---}'])
+
+    # Insert ligature breaks to prevent ligation of hyphens to dashes:
     i = 0
-    while i < len(document.body):
-        words = document.body[i].split()
-        if len(words) > 1 and words[0] == "\\begin_inset" and \
-           words[1] in ["CommandInset", "ERT", "External", "Formula", "Graphics", "IPA", "listings"]:
-            # see convert_dashes
-            j = find_end_of_inset(document.body, i)
-            if j == -1:
-                document.warning("Malformed LyX document: Can't find end of " + words[1] + " inset at line " + str(i))
-                i += 1
-            else:
-                i = j
+    while True:
+        i = find_substring(document.body, "--", i+1)
+        if i == -1:
+            break
+        line = document.body[i]
+        # skip label width string (bug 10243):
+        if line.startswith("\\labelwidthstring"):
             continue
-        replaced = False
-        if document.body[i].find("\\twohyphens") >= 0:
-            document.body[i] = document.body[i].replace("\\twohyphens", "--")
-            replaced = True
-        if document.body[i].find("\\threehyphens") >= 0:
-            document.body[i] = document.body[i].replace("\\threehyphens", "---")
-            replaced = True
-        if replaced and i+1 < len(document.body) and \
-           (document.body[i+1].find("\\") != 0 or \
-            document.body[i+1].find("\\twohyphens") == 0 or
-            document.body[i+1].find("\\threehyphens") == 0) and \
-           len(document.body[i]) + len(document.body[i+1]) <= 80:
-            document.body[i] = document.body[i] + document.body[i+1]
-            document.body[i+1:i+2] = []
+        # do not touch hyphens in some insets (cf. convert_dashes):
+        try:
+            value, start, end = get_containing_inset(document.body, i)
+        except TypeError:
+            # False means no (or malformed) containing inset
+            value, start, end = "no inset", -1, -1
+        if (value.split()[0] in ["CommandInset", "ERT", "External", "Formula",
+                                 "FormulaMacro", "Graphics", "IPA", "listings"]
+            or value == "Flex URL"):
+            i = end
+            continue
+        line = line.replace("--", "-\\SpecialChar \\textcompwordmark{}\n-")
+        document.body[i:i+1] = line.split('\n')
+
+    # Revert \twohyphens and \threehyphens:
+    i = 1
+    while i < len(document.body):
+        line = document.body[i]
+        if not line.endswith("hyphens"):
+            i +=1
+        elif line.endswith("\\twohyphens") or line.endswith("\\threehyphens"):
+            line = line.replace("\\twohyphens", "--")
+            line = line.replace("\\threehyphens", "---")
+            document.body[i] = line + document.body.pop(i+1)
         else:
             i += 1
 
@@ -729,27 +738,26 @@ def convert_phrases(document):
     if document.backend != "latex":
         return
 
-    for phrase in phrases:
-        i = 0
-        while i < len(document.body):
+    i = 0
+    while i < len(document.body):
+        if document.body[i] and document.body[i][0] == "\\":
             words = document.body[i].split()
             if len(words) > 1 and words[0] == "\\begin_inset" and \
-               words[1] in ["CommandInset", "External", "Formula", "Graphics", "listings"]:
+            words[1] in ["CommandInset", "External", "Formula", "Graphics", "listings"]:
                 # must not replace anything in insets that store LaTeX contents in .lyx files
-                # (math and command insets withut overridden read() and write() methods
+                # (math and command insets without overridden read() and write() methods)
                 j = find_end_of_inset(document.body, i)
                 if j == -1:
-                    document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
+                    document.warning("Malformed LyX document: Can't find end of inset at line %d" % (i))
                     i += 1
                 else:
                     i = j
-                continue
-            if document.body[i].find("\\") == 0:
+            else:
                 i += 1
-                continue
+            continue
+        for phrase in phrases:
             j = document.body[i].find(phrase)
             if j == -1:
-                i += 1
                 continue
             if not is_part_of_converted_phrase(document.body[i], j, phrase):
                 front = document.body[i][:j]
@@ -758,11 +766,11 @@ def convert_phrases(document):
                     document.body.insert(i+1, back)
                 # We cannot use SpecialChar since we do not know whether we are outside passThru
                 document.body[i] = front + "\\SpecialCharNoPassThru \\" + phrase
-            i += 1
+        i += 1
 
 
 def revert_phrases(document):
-    "convert special phrases to plain text"
+    "revert special phrases to plain text"
 
     i = 0
     while i < len(document.body):
@@ -807,16 +815,21 @@ def convert_specialchar_internal(document, forward):
 
     i = 0
     while i < len(document.body):
-        words = document.body[i].split()
-        if len(words) > 1 and words[0] == "\\begin_inset" and \
-           words[1] in ["CommandInset", "External", "Formula", "Graphics", "listings"]:
-            # see convert_phrases
-            j = find_end_of_inset(document.body, i)
-            if j == -1:
-                document.warning("Malformed LyX document: Can't find end of Formula inset at line " + str(i))
-                i += 1
-            else:
-                i = j
+        if document.body[i] and document.body[i][0] == "\\":
+            words = document.body[i].split()
+            if len(words) > 1 and words[0] == "\\begin_inset" and \
+            words[1] in ["CommandInset", "External", "Formula", "Graphics", "listings"]:
+                # see convert_phrases
+                j = find_end_of_inset(document.body, i)
+                if j == -1:
+                    document.warning("Malformed LyX document: Can't find end of %s inset at line %d" % (words[1], i))
+                    i += 1
+                else:
+                    i = j
+                continue
+            # else...
+        if not "\\SpecialChar" in document.body[i]:
+            i += 1
             continue
         for key, value in specialchars.items():
             if forward:
@@ -845,16 +858,11 @@ def revert_georgian(document):
         document.language = "english"
         i = find_token(document.header, "\\language georgian", 0)
         if i != -1:
-           document.header[i] = "\\language english"
+            document.header[i] = "\\language english"
         j = find_token(document.header, "\\language_package default", 0)
         if j != -1:
-           document.header[j] = "\\language_package babel"
-        k = find_token(document.header, "\\options", 0)
-        if k != -1:
-           document.header[k] = document.header[k].replace("\\options", "\\options georgian,")
-        else:
-           l = find_token(document.header, "\\use_default_options", 0)
-           document.header.insert(l + 1, "\\options georgian")
+            document.header[j] = "\\language_package babel"
+        insert_document_option(document, "georgian")
 
 
 def revert_sigplan_doi(document):
@@ -1243,67 +1251,65 @@ def revert_textcolor(document):
 
 
 def convert_colorbox(document):
-    " adds color settings for boxes "
-
-    i = 0
+    "Add color settings for boxes."
+    i = 1
     while True:
         i = find_token(document.body, "shadowsize", i)
         if i == -1:
             return
-        document.body[i+1:i+1] = ['framecolor "black"', 'backgroundcolor "none"']
-        i = i + 3
+        # check whether this is really a LyX Box setting
+        start, end = is_in_inset(document.body, i, "\\begin_inset Box")
+        if (end == -1 or
+            find_token(document.body, "\\begin_layout", start, i) != -1):
+            i += 1
+            continue
+        document.body[i+1:i+1] = ['framecolor "black"',
+                                  'backgroundcolor "none"']
+        i += 3
 
 
 def revert_colorbox(document):
-    " outputs color settings for boxes as TeX code "
-    
+    """Change box color settings to LaTeX code."""
+
     i = 0
-    defaultframecolor = "black"
-    defaultbackcolor = "none"
     while True:
-        i = find_token(document.body, "framecolor", i)
+        i = find_token(document.body, "\\begin_inset Box", i+1)
         if i == -1:
             return
-        binset = find_token(document.body, "\\begin_inset Box", i - 14)
-        if binset == -1:
-            return
-        einset = find_end_of_inset(document.body, binset)
+        # Get and delete colour settings:
+        framecolor = get_quoted_value(document.body, "framecolor", i+14, i+15, delete=True)
+        backcolor = get_quoted_value(document.body, "backgroundcolor", i+14, i+15, delete=True)
+        if not framecolor or not backcolor:
+            document.warning("Malformed LyX document: color options not found in Box inset!")
+            continue
+        if framecolor == "black" and backcolor == "none": # default values
+            i += 15 # skip box option lines
+            continue
+
+        # Emulate non-default colours with LaTeX code:
+        einset = find_end_of_inset(document.body, i)
         if einset == -1:
             document.warning("Malformed LyX document: Can't find end of box inset!")
             continue
-        # read out the values
-        beg = document.body[i].find('"');
-        end = document.body[i].rfind('"');
-        framecolor = document.body[i][beg+1:end];
-        beg = document.body[i + 1].find('"');
-        end = document.body[i + 1].rfind('"');
-        backcolor = document.body[i+1][beg+1:end];
-        # delete the specification
-        del document.body[i:i + 2]
-        # output ERT
-        # first output the closing brace
-        if framecolor != defaultframecolor or backcolor != defaultbackcolor:
-            add_to_preamble(document, ["\\@ifundefined{rangeHsb}{\\usepackage{xcolor}}{}"])
-            document.body[einset : einset] = put_cmd_in_ert("}")
-        # determine the box type
-        isBox = find_token(document.body, "\\begin_inset Box Boxed", binset)
-        # now output the box commands
-        if (framecolor != defaultframecolor and isBox == binset) or (backcolor != defaultbackcolor and isBox == binset):
-            document.body[i - 14 : i - 14] = put_cmd_in_ert("\\fcolorbox{" + framecolor + "}{" + backcolor + "}{")
-            # in the case we must also change the box type because the ERT code adds a frame
-            document.body[i - 4] = "\\begin_inset Box Frameless"
-            # if has_inner_box 0 we must set it and use_makebox to 1
-            ibox = find_token(document.body, "has_inner_box", i - 4)
-            if ibox == -1 or ibox != i - 1:
-                document.warning("Malformed LyX document: Can't find has_inner_box statement!")
-                continue
-            # read out the value
-            innerbox = document.body[ibox][-1:];
-            if innerbox == "0":
-                document.body[ibox] = "has_inner_box 1"
-                document.body[ibox + 3] = "use_makebox 1"
-        if backcolor != defaultbackcolor and isBox != binset:
-            document.body[i - 14 : i - 14] =  put_cmd_in_ert("\\colorbox{" + backcolor + "}{")
+        add_to_preamble(document, ["\\@ifundefined{rangeHsb}{\\usepackage{xcolor}}{}"])
+        # insert the closing brace first (keeps indices 'i' and 'einset' valid)
+        document.body[einset+1:einset+1] = put_cmd_in_ert("}") + [""]
+        # now insert the (f)color box command
+        if ("Box Boxed" in document.body[i]): # framed box, use \fcolorbox
+            # change the box type (frame added by \fcolorbox)
+            document.body[i] = "\\begin_inset Box Frameless"
+            # ensure an inner box:
+            try:
+                if not set_bool_value(document.body, "has_inner_box", True, i+3, i+4):
+                    set_bool_value(document.body, "use_makebox", True, i+6, i+7)
+            except ValueError:
+                document.warning("Malformed LyX document: 'has_inner_box' or "
+                                 "'use_makebox' option not found in box inset!")
+            ertinset = put_cmd_in_ert("\\fcolorbox{%s}{%s}{"% (framecolor, backcolor))
+        else:
+            ertinset = put_cmd_in_ert("\\colorbox{%s}{" % backcolor)
+        document.body[i:i] = ertinset + [""]
+        i = einset # skip inset
 
 
 def revert_mathmulticol(document):