示例#1
0
 def _fix_text_styling(self):
     lines = self.lines
     self.stack = []
     stack = self.stack
     fixes = []
     # First we'll rename the \color in the header, if any.
     i = find_tokens(lines, ('\\color', '\\end_header'), 0)
     if i != -1 and \
        check_token(lines[i], '\\color') and \
        not get_containing_layout(lines, i):
         lines[i] = '\\color_in_header ' + lines[i].split()[1]
     # Now let's get on with the rest
     i = 0
     while i < len(lines):
         line = lines[i]
         self.dbg(4, 'looking at line %d: %s' % (i, line))
         # XXX We really should simplify all this startswith()
         # nonsense.
         if line.startswith('\\end_'):
             self.dbg(2, 'fixing unended style tags %s' % (repr(stack)))
             for k in range(len(stack) - 1, -1, -1):
                 lines.insert(
                     i, '\\' + stack[k][0] + ' ' + mixed_tags[stack[k][0]])
                 i += 1
             del (stack[0:])
             i += 1
             continue
         if not line.startswith('\\') or line.find(' ') == -1:
             self.dbg(5, '1 i++ at %d' % (i, ))
             i += 1
             continue
         # XXX And this parsing nonsense needs refactoring too
         line = _chomp(line[1:])
         a = line[0:line.find(' ')]
         if not a in mixed_tags:
             self.dbg(5, '2 i++ at %d' % (i, ))
             i += 1
             continue
         v = line[line.find(' ') + 1:]
         # We're opening a new whatever it is.  But we need to handle
         # the possibility that we're changing the whatever it is!
         # How to handle this?  We could convert:
         #  \lang french foo \lang spanish bar \lang english foobar
         # to
         #  <lang a="french">foo<lang a="spanish">bar</lang></lang>
         # or to
         #  <lang a="french">foo</lang><lang a="spanish">bar</lang>
         # The former might be easier: just close all tags up to the
         # farthest one in the stack for the tag being closed, then
         # re-open any others that were found along the way.  But the
         # latter is more sensible, so that's what we do.
         # Invariant: we never have more than one style tag in the
         # stack (XXX assert this in code).
         self.dbg(4, 'seen \\%s at line %d' % (line, i))
         i = self._close_and_reopen_styling(i, a, v)
         self.dbg(5, '3 i++ at %d' % (i, ))
示例#2
0
 def _fix_text_styling(self):
     lines = self.lines
     self.stack = []
     stack = self.stack
     fixes = []
     # First we'll rename the \color in the header, if any.
     i = find_tokens(lines, ('\\color', '\\end_header'), 0)
     if i != -1 and \
        check_token(lines[i], '\\color') and \
        not get_containing_layout(lines, i):
         lines[i] = '\\color_in_header ' + lines[i].split()[1]
     # Now let's get on with the rest
     i = 0
     while i < len(lines):
         line = lines[i]
         self.dbg(4, 'looking at line %d: %s' % (i, line))
         # XXX We really should simplify all this startswith()
         # nonsense.
         if line.startswith('\\end_'):
             self.dbg(2, 'fixing unended style tags %s' % (repr(stack)))
             for k in range(len(stack) - 1, -1, -1):
                 lines.insert(i, '\\' + stack[k][0] + ' ' + mixed_tags[stack[k][0]])
                 i += 1
             del(stack[0:])
             i += 1
             continue
         if not line.startswith('\\') or line.find(' ') == -1:
             self.dbg(5, '1 i++ at %d' % (i,))
             i += 1
             continue
         # XXX And this parsing nonsense needs refactoring too
         line = _chomp(line[1:])
         a = line[0:line.find(' ')]
         if not a in mixed_tags:
             self.dbg(5, '2 i++ at %d' % (i,))
             i += 1
             continue
         v = line[line.find(' ') + 1:]
         # We're opening a new whatever it is.  But we need to handle
         # the possibility that we're changing the whatever it is!
         # How to handle this?  We could convert:
         #  \lang french foo \lang spanish bar \lang english foobar
         # to
         #  <lang a="french">foo<lang a="spanish">bar</lang></lang>
         # or to
         #  <lang a="french">foo</lang><lang a="spanish">bar</lang>
         # The former might be easier: just close all tags up to the
         # farthest one in the stack for the tag being closed, then
         # re-open any others that were found along the way.  But the
         # latter is more sensible, so that's what we do.
         # Invariant: we never have more than one style tag in the
         # stack (XXX assert this in code).
         self.dbg(4, 'seen \\%s at line %d' % (line, i))
         i = self._close_and_reopen_styling(i, a, v)
         self.dbg(5, '3 i++ at %d' % (i,))
示例#3
0
文件: lyx_2_2.py 项目: maxvas/SciLyx
def convert_separator(document):
    """
    Convert layout separators to separator insets and add (LaTeX) paragraph
    breaks in order to mimic previous LaTeX export.
    """

    parins = ["\\begin_inset Separator parbreak", "\\end_inset", ""]
    parlay = ["\\begin_layout Standard", "\\begin_inset Separator parbreak",
              "\\end_inset", "", "\\end_layout", ""]
    sty_dict = {
        "family" : "default",
        "series" : "default",
        "shape"  : "default",
        "size"   : "default",
        "bar"    : "default",
        "color"  : "inherit"
        }

    i = 0
    while 1:
        i = find_token(document.body, "\\begin_deeper", i)
        if i == -1:
            break

        j = find_token_backwards(document.body, "\\end_layout", i-1)
        if j != -1:
            # reset any text style before inserting the inset
            lay = get_containing_layout(document.body, j-1)
            if lay != False:
                content = "\n".join(document.body[lay[1]:lay[2]])
                for val in sty_dict.keys():
                    if content.find("\\%s" % val) != -1:
                        document.body[j:j] = ["\\%s %s" % (val, sty_dict[val])]
                        i = i + 1
                        j = j + 1
            document.body[j:j] = parins
            i = i + len(parins) + 1
        else:
            i = i + 1

    i = 0
    while 1:
        i = find_token(document.body, "\\align", i)
        if i == -1:
            break

        lay = get_containing_layout(document.body, i)
        if lay != False and lay[0] == "Plain Layout":
            i = i + 1
            continue

        j = find_token_backwards(document.body, "\\end_layout", i-1)
        if j != -1:
            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 \
               and find_token(document.body, "\\begin_inset VSpace", lay[1], lay[2]) == -1:
                # reset any text style before inserting the inset
                content = "\n".join(document.body[lay[1]:lay[2]])
                for val in sty_dict.keys():
                    if content.find("\\%s" % val) != -1:
                        document.body[j:j] = ["\\%s %s" % (val, sty_dict[val])]
                        i = i + 1
                        j = j + 1
                document.body[j:j] = parins
                i = i + len(parins) + 1
            else:
                i = i + 1
        else:
            i = i + 1

    regexp = re.compile(r'^\\begin_layout (?:(-*)|(\s*))(Separator|EndOfSlide)(?:(-*)|(\s*))$', re.IGNORECASE)

    i = 0
    while 1:
        i = find_re(document.body, regexp, i)
        if i == -1:
            return

        j = find_end_of_layout(document.body, i)
        if j == -1:
            document.warning("Malformed LyX document: Missing `\\end_layout'.")
            return

        lay = get_containing_layout(document.body, j-1)
        if lay != False:
            lines = document.body[lay[3]:lay[2]]
        else:
            lines = []

        document.body[i:j+1] = parlay
        if len(lines) > 0:
            document.body[i+1:i+1] = lines

        i = i + len(parlay) + len(lines) + 1
示例#4
0
文件: lyx_2_2.py 项目: maxvas/SciLyx
def revert_separator(document):
    " Revert separator insets to layout separators "

    beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
    if document.textclass in beamer_classes:
        beglaysep = "\\begin_layout Separator"
    else:
        beglaysep = "\\begin_layout --Separator--"

    parsep = [beglaysep, "", "\\end_layout", ""]
    comert = ["\\begin_inset ERT", "status collapsed", "",
              "\\begin_layout Plain Layout", "%", "\\end_layout",
              "", "\\end_inset", ""]
    empert = ["\\begin_inset ERT", "status collapsed", "",
              "\\begin_layout Plain Layout", " ", "\\end_layout",
              "", "\\end_inset", ""]

    i = 0
    while 1:
        i = find_token(document.body, "\\begin_inset Separator", i)
        if i == -1:
            return

        lay = get_containing_layout(document.body, i)
        if lay == False:
            document.warning("Malformed LyX document: Can't convert separator inset at line " + str(i))
            i = i + 1
            continue

        layoutname = lay[0]
        beg = lay[1]
        end = lay[2]
        kind = get_value(document.body, "\\begin_inset Separator", i, i+1, "plain").split()[1]
        before = document.body[beg+1:i]
        something_before = len(before) > 0 and len("".join(before)) > 0
        j = find_end_of_inset(document.body, i)
        after = document.body[j+1:end]
        something_after = len(after) > 0 and len("".join(after)) > 0
        if kind == "plain":
            beg = beg + len(before) + 1
        elif something_before:
            document.body[i:i] = ["\\end_layout", ""]
            i = i + 2
            j = j + 2
            beg = i
            end = end + 2

        if kind == "plain":
            if something_after:
                document.body[beg:j+1] = empert
                i = i + len(empert)
            else:
                document.body[beg:j+1] = comert
                i = i + len(comert)
        else:
            if something_after:
                if layoutname == "Standard":
                    if not something_before:
                        document.body[beg:j+1] = parsep
                        i = i + len(parsep)
                        document.body[i:i] = ["", "\\begin_layout Standard"]
                        i = i + 2
                    else:
                        document.body[beg:j+1] = ["\\begin_layout Standard"]
                        i = i + 1
                else:
                    document.body[beg:j+1] = ["\\begin_deeper"]
                    i = i + 1
                    end = end + 1 - (j + 1 - beg)
                    if not something_before:
                        document.body[i:i] = parsep
                        i = i + len(parsep)
                        end = end + len(parsep)
                    document.body[i:i] = ["\\begin_layout Standard"]
                    document.body[end+2:end+2] = ["", "\\end_deeper", ""]
                    i = i + 4
            else:
                next_par_is_aligned = False
                k = find_nonempty_line(document.body, end+1)
                if k != -1 and check_token(document.body[k], "\\begin_layout"):
                    lay = get_containing_layout(document.body, k)
                    next_par_is_aligned = lay != False and \
                            find_token(document.body, "\\align", lay[1], lay[2]) != -1
                if k != -1 and not next_par_is_aligned \
                        and not check_token(document.body[k], "\\end_deeper") \
                        and not check_token(document.body[k], "\\begin_deeper"):
                    if layoutname == "Standard":
                        document.body[beg:j+1] = [beglaysep]
                        i = i + 1
                    else:
                        document.body[beg:j+1] = ["\\begin_deeper", beglaysep]
                        end = end + 2 - (j + 1 - beg)
                        document.body[end+1:end+1] = ["", "\\end_deeper", ""]
                        i = i + 3
                else:
                    if something_before:
                        del document.body[i:end+1]
                    else:
                        del document.body[i:end-1]

        i = i + 1
示例#5
0
def convert_separator(document):
    """
    Convert layout separators to separator insets and add (LaTeX) paragraph
    breaks in order to mimic previous LaTeX export.
    """

    parins = ["\\begin_inset Separator parbreak", "\\end_inset", ""]
    parlay = [
        "\\begin_layout Standard", "\\begin_inset Separator parbreak",
        "\\end_inset", "", "\\end_layout", ""
    ]
    sty_dict = {
        "family": "default",
        "series": "default",
        "shape": "default",
        "size": "default",
        "bar": "default",
        "color": "inherit"
    }

    i = 0
    while 1:
        i = find_token(document.body, "\\begin_deeper", i)
        if i == -1:
            break

        j = find_token_backwards(document.body, "\\end_layout", i - 1)
        if j != -1:
            # reset any text style before inserting the inset
            lay = get_containing_layout(document.body, j - 1)
            if lay != False:
                content = "\n".join(document.body[lay[1]:lay[2]])
                for val in sty_dict.keys():
                    if content.find("\\%s" % val) != -1:
                        document.body[j:j] = ["\\%s %s" % (val, sty_dict[val])]
                        i = i + 1
                        j = j + 1
            document.body[j:j] = parins
            i = i + len(parins) + 1
        else:
            i = i + 1

    i = 0
    while 1:
        i = find_token(document.body, "\\align", i)
        if i == -1:
            break

        lay = get_containing_layout(document.body, i)
        if lay != False and lay[0] == "Plain Layout":
            i = i + 1
            continue

        j = find_token_backwards(document.body, "\\end_layout", i - 1)
        if j != -1:
            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 \
               and find_token(document.body, "\\begin_inset VSpace", lay[1], lay[2]) == -1:
                # reset any text style before inserting the inset
                content = "\n".join(document.body[lay[1]:lay[2]])
                for val in sty_dict.keys():
                    if content.find("\\%s" % val) != -1:
                        document.body[j:j] = ["\\%s %s" % (val, sty_dict[val])]
                        i = i + 1
                        j = j + 1
                document.body[j:j] = parins
                i = i + len(parins) + 1
            else:
                i = i + 1
        else:
            i = i + 1

    regexp = re.compile(
        r'^\\begin_layout (?:(-*)|(\s*))(Separator|EndOfSlide)(?:(-*)|(\s*))$',
        re.IGNORECASE)

    i = 0
    while 1:
        i = find_re(document.body, regexp, i)
        if i == -1:
            return

        j = find_end_of_layout(document.body, i)
        if j == -1:
            document.warning("Malformed LyX document: Missing `\\end_layout'.")
            return

        lay = get_containing_layout(document.body, j - 1)
        if lay != False:
            lines = document.body[lay[3]:lay[2]]
        else:
            lines = []

        document.body[i:j + 1] = parlay
        if len(lines) > 0:
            document.body[i + 1:i + 1] = lines

        i = i + len(parlay) + len(lines) + 1
示例#6
0
def revert_separator(document):
    " Revert separator insets to layout separators "

    beamer_classes = ["beamer", "article-beamer", "scrarticle-beamer"]
    if document.textclass in beamer_classes:
        beglaysep = "\\begin_layout Separator"
    else:
        beglaysep = "\\begin_layout --Separator--"

    parsep = [beglaysep, "", "\\end_layout", ""]
    comert = [
        "\\begin_inset ERT", "status collapsed", "",
        "\\begin_layout Plain Layout", "%", "\\end_layout", "", "\\end_inset",
        ""
    ]
    empert = [
        "\\begin_inset ERT", "status collapsed", "",
        "\\begin_layout Plain Layout", " ", "\\end_layout", "", "\\end_inset",
        ""
    ]

    i = 0
    while 1:
        i = find_token(document.body, "\\begin_inset Separator", i)
        if i == -1:
            return

        lay = get_containing_layout(document.body, i)
        if lay == False:
            document.warning(
                "Malformed LyX document: Can't convert separator inset at line "
                + str(i))
            i = i + 1
            continue

        layoutname = lay[0]
        beg = lay[1]
        end = lay[2]
        kind = get_value(document.body, "\\begin_inset Separator", i, i + 1,
                         "plain").split()[1]
        before = document.body[beg + 1:i]
        something_before = len(before) > 0 and len("".join(before)) > 0
        j = find_end_of_inset(document.body, i)
        after = document.body[j + 1:end]
        something_after = len(after) > 0 and len("".join(after)) > 0
        if kind == "plain":
            beg = beg + len(before) + 1
        elif something_before:
            document.body[i:i] = ["\\end_layout", ""]
            i = i + 2
            j = j + 2
            beg = i
            end = end + 2

        if kind == "plain":
            if something_after:
                document.body[beg:j + 1] = empert
                i = i + len(empert)
            else:
                document.body[beg:j + 1] = comert
                i = i + len(comert)
        else:
            if something_after:
                if layoutname == "Standard":
                    if not something_before:
                        document.body[beg:j + 1] = parsep
                        i = i + len(parsep)
                        document.body[i:i] = ["", "\\begin_layout Standard"]
                        i = i + 2
                    else:
                        document.body[beg:j + 1] = ["\\begin_layout Standard"]
                        i = i + 1
                else:
                    document.body[beg:j + 1] = ["\\begin_deeper"]
                    i = i + 1
                    end = end + 1 - (j + 1 - beg)
                    if not something_before:
                        document.body[i:i] = parsep
                        i = i + len(parsep)
                        end = end + len(parsep)
                    document.body[i:i] = ["\\begin_layout Standard"]
                    document.body[end + 2:end + 2] = ["", "\\end_deeper", ""]
                    i = i + 4
            else:
                next_par_is_aligned = False
                k = find_nonempty_line(document.body, end + 1)
                if k != -1 and check_token(document.body[k], "\\begin_layout"):
                    lay = get_containing_layout(document.body, k)
                    next_par_is_aligned = lay != False and \
                            find_token(document.body, "\\align", lay[1], lay[2]) != -1
                if k != -1 and not next_par_is_aligned \
                        and not check_token(document.body[k], "\\end_deeper") \
                        and not check_token(document.body[k], "\\begin_deeper"):
                    if layoutname == "Standard":
                        document.body[beg:j + 1] = [beglaysep]
                        i = i + 1
                    else:
                        document.body[beg:j +
                                      1] = ["\\begin_deeper", beglaysep]
                        end = end + 2 - (j + 1 - beg)
                        document.body[end + 1:end +
                                      1] = ["", "\\end_deeper", ""]
                        i = i + 3
                else:
                    if something_before:
                        del document.body[i:end + 1]
                    else:
                        del document.body[i:end - 1]

        i = i + 1
示例#7
0
def revert_language(document, lyxname, babelname="", polyglossianame=""):
    " Revert native language support "

    # Does the document use polyglossia?
    use_polyglossia = False
    if get_bool_value(document.header, "\\use_non_tex_fonts"):
        i = find_token(document.header, "\\language_package")
        if i == -1:
            document.warning("Malformed document! Missing \\language_package")
        else:
            pack = get_value(document.header, "\\language_package", i)
            if pack == "default" or pack == "auto":
                use_polyglossia = True

    # Do we use this language with polyglossia?
    with_polyglossia = use_polyglossia and polyglossianame != ""
    # Do we use this language with babel?
    with_babel = with_polyglossia == False and babelname != ""

    # Are we dealing with a primary or secondary language?
    primary = document.language == lyxname
    secondary = False

    # Main language first
    orig_doc_language = document.language
    if primary:
        # Change LyX document language to English (we will tell LaTeX
        # to use the original language at the end of this function):
        document.language = "english"
        i = find_token(document.header, "\\language %s" % lyxname, 0)
        if i != -1:
            document.header[i] = "\\language english"

    # Now look for occurences in the body
    i = 0
    while True:
        i = find_token(document.body, "\\lang", i+1)
        if i == -1:
            break
        if document.body[i].startswith("\\lang %s" % lyxname):
            secondary = True
            texname = use_polyglossia and polyglossianame or babelname
        elif primary and document.body[i].startswith("\\lang english"):
            # Since we switched the main language manually, English parts need to be marked
            texname = "english"
        else:
            continue

        parent = get_containing_layout(document.body, i)
        i_e = parent[2] # end line no,
        # print(i, texname, parent, document.body[i+1], file=sys.stderr)
        
        # Move leading space to the previous line:
        if document.body[i+1].startswith(" "):
            document.body[i+1] = document.body[i+1][1:]
            document.body.insert(i, " ")
            continue
        
        # Ensure correct handling of list labels
        if (parent[0] in ["Labeling", "Description"]
            and not " " in "\n".join(document.body[parent[3]:i])):
            # line `i+1` is first line of a list item,
            # part before a space character is the label
            # TODO: insets or language change before first space character
            labelline = document.body[i+1].split(' ', 1)
            if len(labelline) > 1:
                # Insert a space in the (original) document language
                # between label and remainder.
                # print("  Label:", labelline, file=sys.stderr)
                lines = [labelline[0],
                    "\\lang %s" % orig_doc_language,
                    " ",
                    "\\lang %s" % (primary and "english" or lyxname),
                    labelline[1]]
                document.body[i+1:i+2] = lines
                i_e += 4
  
        # Find out where to end the language change.
        langswitch = i
        while True:
            langswitch = find_token(document.body, "\\lang", langswitch+1, i_e)
            if langswitch == -1:
                break
            # print("  ", langswitch, document.body[langswitch], file=sys.stderr)
            # skip insets
            i_a = parent[3] # paragraph start line
            container = get_containing_inset(document.body[i_a:i_e], langswitch-i_a)
            if container and container[1] < langswitch-i_a and container[2] > langswitch-i_a:
                # print("  inset", container, file=sys.stderr)
                continue
            i_e = langswitch
            break
        
        # use function or environment?
        singlepar = i_e - i < 3
        if not singlepar and parent[0] == "Plain Layout":
            # environment not allowed in some insets
            container = get_containing_inset(document.body, i)
            singlepar = container[0] in singlepar_insets
            
        # Delete empty language switches:
        if not "".join(document.body[i+1:i_e]):
            del document.body[i:i_e]
            i -= 1
            continue

        if singlepar:
            if with_polyglossia:
                begin_cmd = "\\text%s{"%texname
            elif with_babel:
                begin_cmd = "\\foreignlanguage{%s}{" % texname
            end_cmd = "}"
        else:
            if with_polyglossia:
                begin_cmd = "\\begin{%s}"%texname
                end_cmd = "\\end{%s}"%texname
            elif with_babel:
                begin_cmd = "\\begin{otherlanguage}{%s}" % texname
                end_cmd = "\\end{otherlanguage}"

        if (not primary or texname == "english"):
            document.body[i_e:i_e] = put_cmd_in_ert(end_cmd)
            document.body[i+1:i+1] = put_cmd_in_ert(begin_cmd)
        del document.body[i]

    if not (primary or secondary):
        return

    # Make the language known to Babel/Polyglossia and ensure the correct
    # document language:
    doc_lang_switch = ""
    if with_babel:
        # add as global option
        insert_document_option(document, babelname)
        # Since user options are appended to the document options,
        # Babel will treat `babelname` as primary language.
        if not primary:
            doc_lang_switch = "\\selectlanguage{%s}" % orig_doc_language
    if with_polyglossia:
        # Define language in the user preamble
        # (don't use \AtBeginDocument, this fails with some languages).
        add_to_preamble(document, ["\\usepackage{polyglossia}",
                                   "\\setotherlanguage{%s}" % polyglossianame])
        if primary:
            # Changing the main language must be done in the document body.
            doc_lang_switch = "\\resetdefaultlanguage{%s}" % polyglossianame

    # Reset LaTeX main language if required and not already done
    if doc_lang_switch and doc_lang_switch not in document.body[8:20] != doc_lang_switch:
        document.body[2:2] = put_cmd_in_ert(doc_lang_switch,
                                            is_open=True, as_paragraph=True)
def revert_language(document, lyxname, babelname="", polyglossianame=""):
    " Revert native language support "

    # Does the document use polyglossia?
    use_polyglossia = False
    if get_bool_value(document.header, "\\use_non_tex_fonts"):
        i = find_token(document.header, "\\language_package")
        if i == -1:
            document.warning("Malformed document! Missing \\language_package")
        else:
            pack = get_value(document.header, "\\language_package", i)
            if pack in ("default", "auto"):
                use_polyglossia = True

    # Do we use this language with polyglossia?
    with_polyglossia = use_polyglossia and polyglossianame != ""
    # Do we use this language with babel?
    with_babel = with_polyglossia == False and babelname != ""

    # Are we dealing with a primary or secondary language?
    primary = document.language == lyxname
    secondary = False

    # Main language first
    orig_doc_language = document.language
    if primary:
        # Change LyX document language to English (we will tell LaTeX
        # to use the original language at the end of this function):
        document.language = "english"
        i = find_token(document.header, "\\language %s" % lyxname, 0)
        if i != -1:
            document.header[i] = "\\language english"

    # Now look for occurences in the body
    i = 0
    while True:
        i = find_token(document.body, "\\lang", i + 1)
        if i == -1:
            break
        if document.body[i].startswith("\\lang %s" % lyxname):
            secondary = True
            texname = use_polyglossia and polyglossianame or babelname
        elif primary and document.body[i].startswith("\\lang english"):
            # Since we switched the main language manually, English parts need to be marked
            texname = "english"
        else:
            continue

        parent = get_containing_layout(document.body, i)
        i_e = parent[2]  # end line no,
        # print(i, texname, parent, document.body[i+1], file=sys.stderr)

        # Move leading space to the previous line:
        if document.body[i + 1].startswith(" "):
            document.body[i + 1] = document.body[i + 1][1:]
            document.body.insert(i, " ")
            continue

        # TODO: handle nesting issues with font attributes, e.g.
        # \begin_layout Standard
        #
        # \emph on
        # \lang macedonian
        # Македонски јазик
        # \emph default
        #  — јужнословенски јазик, дел од групата на словенски јазици од јазичното
        #  семејство на индоевропски јазици.
        #  Македонскиот е службен и национален јазик во Македонија.
        # \end_layout

        # Ensure correct handling of list labels
        if (parent[0] in ["Labeling", "Description"]
                and not " " in "\n".join(document.body[parent[3]:i])):
            # line `i+1` is first line of a list item,
            # part before a space character is the label
            # TODO: insets or language change before first space character
            labelline = document.body[i + 1].split(' ', 1)
            if len(labelline) > 1:
                # Insert a space in the (original) document language
                # between label and remainder.
                # print("  Label:", labelline, file=sys.stderr)
                lines = [
                    labelline[0],
                    "\\lang %s" % orig_doc_language, " ",
                    "\\lang %s" % (primary and "english" or lyxname),
                    labelline[1]
                ]
                document.body[i + 1:i + 2] = lines
                i_e += 4

        # Find out where to end the language change.
        langswitch = i
        while True:
            langswitch = find_token(document.body, "\\lang", langswitch + 1,
                                    i_e)
            if langswitch == -1:
                break
            # print("  ", langswitch, document.body[langswitch], file=sys.stderr)
            # skip insets
            i_a = parent[3]  # paragraph start line
            container = get_containing_inset(document.body[i_a:i_e],
                                             langswitch - i_a)
            if container and container[1] < langswitch - i_a and container[
                    2] > langswitch - i_a:
                # print("  inset", container, file=sys.stderr)
                continue
            i_e = langswitch
            break

        # use function or environment?
        singlepar = i_e - i < 3
        if not singlepar and parent[0] == "Plain Layout":
            # environment not allowed in some insets
            container = get_containing_inset(document.body, i)
            singlepar = container[0] in singlepar_insets

        # Delete empty language switches:
        if not "".join(document.body[i + 1:i_e]):
            del document.body[i:i_e]
            i -= 1
            continue

        if singlepar:
            if with_polyglossia:
                begin_cmd = "\\text%s{" % texname
            elif with_babel:
                begin_cmd = "\\foreignlanguage{%s}{" % texname
            end_cmd = "}"
        else:
            if with_polyglossia:
                begin_cmd = "\\begin{%s}" % texname
                end_cmd = "\\end{%s}" % texname
            elif with_babel:
                begin_cmd = "\\begin{otherlanguage}{%s}" % texname
                end_cmd = "\\end{otherlanguage}"

        if (not primary or texname == "english"):
            try:
                document.body[i_e:i_e] = put_cmd_in_ert(end_cmd)
                document.body[i + 1:i + 1] = put_cmd_in_ert(begin_cmd)
            except UnboundLocalError:
                pass
        del document.body[i]

    if not (primary or secondary):
        return

    # Make the language known to Babel/Polyglossia and ensure the correct
    # document language:
    doc_lang_switch = ""
    if with_babel:
        # add as global option
        insert_document_option(document, babelname)
        # Since user options are appended to the document options,
        # Babel will treat `babelname` as primary language.
        if not primary:
            doc_lang_switch = "\\selectlanguage{%s}" % orig_doc_language
    if with_polyglossia:
        # Define language in the user preamble
        # (don't use \AtBeginDocument, this fails with some languages).
        add_to_preamble(document, [
            "\\usepackage{polyglossia}",
            "\\setotherlanguage{%s}" % polyglossianame
        ])
        if primary:
            # Changing the main language must be done in the document body.
            doc_lang_switch = "\\resetdefaultlanguage{%s}" % polyglossianame

    # Reset LaTeX main language if required and not already done
    if doc_lang_switch and doc_lang_switch[1:] not in document.body[8:20]:
        document.body[2:2] = put_cmd_in_ert(doc_lang_switch,
                                            is_open=True,
                                            as_paragraph=True)