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, ))
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,))
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
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
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
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
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)