X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=lib%2Flyx2lyx%2Flyx_2_4.py;h=8436d9a84c1e57e3d5de5814b4c4a94f68101405;hb=69ed8cb89abd291b19ca2a3423d1f368a0d67f71;hp=1c22756447af0e86a3e508a79bb997266a8fcaec;hpb=7f3fd5a809a2dea4ccdabc8f6899e11844d91bc7;p=lyx.git diff --git a/lib/lyx2lyx/lyx_2_4.py b/lib/lyx2lyx/lyx_2_4.py index 1c22756447..8436d9a84c 100644 --- a/lib/lyx2lyx/lyx_2_4.py +++ b/lib/lyx2lyx/lyx_2_4.py @@ -22,26 +22,366 @@ import re, string import unicodedata import sys, os +from datetime import (datetime, date, time) + # Uncomment only what you need to import, please. -from parser_tools import (count_pars_in_inset, find_end_of_inset, find_end_of_layout, -find_token, get_bool_value, get_option_value, get_value, get_quoted_value) -# del_token, del_value, del_complete_lines, +from parser_tools import (count_pars_in_inset, del_token, find_end_of_inset, + find_end_of_layout, find_token, find_token_backwards, find_token_exact, + find_re, get_bool_value, + get_containing_layout, get_option_value, get_value, get_quoted_value) +# del_value, del_complete_lines, # find_complete_lines, find_end_of, -# find_re, find_substring, find_token_backwards, -# get_containing_inset, get_containing_layout, +# find_re, find_substring, +# get_containing_inset, # is_in_inset, set_bool_value -# find_tokens, find_token_exact, check_token +# find_tokens, check_token -from lyx2lyx_tools import (put_cmd_in_ert, add_to_preamble) -# revert_font_attrs, insert_to_preamble, latex_length -# get_ert, lyx2latex, lyx2verbatim, length_in_bp, convert_info_insets -# revert_flex_inset, hex2ratio, str2bool +from lyx2lyx_tools import (put_cmd_in_ert, add_to_preamble, insert_to_preamble, lyx2latex, + revert_language, revert_flex_inset, str2bool) +# revert_font_attrs, latex_length +# get_ert, lyx2verbatim, length_in_bp, convert_info_insets +# revert_flex_inset, hex2ratio #################################################################### # Private helper functions +def add_preamble_fonts(document, fontmap): + " Add collected font-packages with their option to user-preamble" + + for pkg in fontmap: + if len(fontmap[pkg]) > 0: + xoption = "[" + ",".join(fontmap[pkg]) + "]" + else: + xoption = "" + preamble = "\\usepackage%s{%s}" % (xoption, pkg) + add_to_preamble(document, [preamble]) + + +def createkey(pkg, options): + options.sort() + return pkg + ':' + "-".join(options) + +class fontinfo: + def __init__(self): + self.fontname = None # key into font2pkgmap + self.fonttype = None # roman,sans,typewriter,math + self.scaletype = None # None,sf,tt + self.scaleopt = None # None, 'scaled', 'scale' + self.scaleval = 1 + self.package = None + self.options = [] + self.pkgkey = None # key into pkg2fontmap + self.osfopt = None # None, string + self.osfdef = "false" # "false" or "true" + + def addkey(self): + self.pkgkey = createkey(self.package, self.options) + +class fontmapping: + def __init__(self): + self.font2pkgmap = dict() + self.pkg2fontmap = dict() + self.pkginmap = dict() # defines, if a map for package exists + + def expandFontMapping(self, font_list, font_type, scale_type, pkg, scaleopt = None, osfopt = None, osfdef = "false"): + " Expand fontinfo mapping" + # + # fontlist: list of fontnames, each element + # may contain a ','-separated list of needed options + # like e.g. 'IBMPlexSansCondensed,condensed' + # font_type: one of 'roman', 'sans', 'typewriter', 'math' + # scale_type: one of None, 'sf', 'tt' + # pkg: package defining the font. Defaults to fontname if None + # scaleopt: one of None, 'scale', 'scaled', or some other string + # to be used in scale option (e.g. scaled=0.7) + # osfopt: None or some other string to be used in osf option + # osfdef: "true" if osf is default + for fl in font_list: + fe = fontinfo() + fe.fonttype = font_type + fe.scaletype = scale_type + flt = fl.split(",") + font_name = flt[0] + fe.fontname = font_name + fe.options = flt[1:] + fe.scaleopt = scaleopt + fe.osfopt = osfopt + fe.osfdef = osfdef + if pkg == None: + fe.package = font_name + else: + fe.package = pkg + fe.addkey() + self.font2pkgmap[font_name] = fe + if fe.pkgkey in self.pkg2fontmap: + # Repeated the same entry? Check content + if self.pkg2fontmap[fe.pkgkey] != font_name: + document.error("Something is wrong in pkgname+options <-> fontname mapping") + self.pkg2fontmap[fe.pkgkey] = font_name + self.pkginmap[fe.package] = 1 + + def getfontname(self, pkg, options): + options.sort() + pkgkey = createkey(pkg, options) + if not pkgkey in self.pkg2fontmap: + return None + fontname = self.pkg2fontmap[pkgkey] + if not fontname in self.font2pkgmap: + document.error("Something is wrong in pkgname+options <-> fontname mapping") + return None + if pkgkey == self.font2pkgmap[fontname].pkgkey: + return fontname + return None + +def createFontMapping(fontlist): + # Create info for known fonts for the use in + # convert_latexFonts() and + # revert_latexFonts() + # + # * Would be more handy to parse latexFonts file, + # but the path to this file is unknown + # * For now, add DejaVu and IBMPlex only. + # * Expand, if desired + fm = fontmapping() + for font in fontlist: + if font == 'DejaVu': + fm.expandFontMapping(['DejaVuSerif', 'DejaVuSerifCondensed'], "roman", None, None) + fm.expandFontMapping(['DejaVuSans','DejaVuSansCondensed'], "sans", "sf", None, "scaled") + fm.expandFontMapping(['DejaVuSansMono'], "typewriter", "tt", None, "scaled") + elif font == 'IBM': + fm.expandFontMapping(['IBMPlexSerif', 'IBMPlexSerifThin,thin', + 'IBMPlexSerifExtraLight,extralight', 'IBMPlexSerifLight,light', + 'IBMPlexSerifSemibold,semibold'], + "roman", None, "plex-serif") + fm.expandFontMapping(['IBMPlexSans','IBMPlexSansCondensed,condensed', + 'IBMPlexSansThin,thin', 'IBMPlexSansExtraLight,extralight', + 'IBMPlexSansLight,light', 'IBMPlexSansSemibold,semibold'], + "sans", "sf", "plex-sans", "scale") + fm.expandFontMapping(['IBMPlexMono', 'IBMPlexMonoThin,thin', + 'IBMPlexMonoExtraLight,extralight', 'IBMPlexMonoLight,light', + 'IBMPlexMonoSemibold,semibold'], + "typewriter", "tt", "plex-mono", "scale") + elif font == 'Adobe': + fm.expandFontMapping(['ADOBESourceSerifPro'], "roman", None, "sourceserifpro", None, "osf") + fm.expandFontMapping(['ADOBESourceSansPro'], "sans", "sf", "sourcesanspro", "scaled", "osf") + fm.expandFontMapping(['ADOBESourceCodePro'], "typewriter", "tt", "sourcecodepro", "scaled", "osf") + elif font == 'Noto': + fm.expandFontMapping(['NotoSerifRegular,regular', 'NotoSerifMedium,medium', + 'NotoSerifThin,thin', 'NotoSerifLight,light', + 'NotoSerifExtralight,extralight'], + "roman", None, "noto-serif", None, "osf") + fm.expandFontMapping(['NotoSansRegular,regular', 'NotoSansMedium,medium', + 'NotoSansThin,thin', 'NotoSansLight,light', + 'NotoSansExtralight,extralight'], + "sans", "sf", "noto-sans", "scaled") + fm.expandFontMapping(['NotoMonoRegular,regular'], "typewriter", "tt", "noto-mono", "scaled") + elif font == 'Cantarell': + fm.expandFontMapping(['cantarell,defaultsans'], + "sans", "sf", "cantarell", "scaled", "oldstyle") + elif font == 'Chivo': + fm.expandFontMapping(['ChivoThin,thin', 'ChivoLight,light', + 'Chivo,regular', 'ChivoMedium,medium'], + "sans", "sf", "Chivo", "scale", "oldstyle") + elif font == 'CrimsonPro': + fm.expandFontMapping(['CrimsonPro', 'CrimsonProExtraLight,extralight', 'CrimsonProLight,light', + 'CrimsonProMedium,medium'], + "roman", None, "CrimsonPro", None, "lf", "true") + elif font == 'Fira': + fm.expandFontMapping(['FiraSans', 'FiraSansBook,book', + 'FiraSansThin,thin', 'FiraSansLight,light', + 'FiraSansExtralight,extralight', + 'FiraSansUltralight,ultralight'], + "sans", "sf", "FiraSans", "scaled", "lf", "true") + fm.expandFontMapping(['FiraMono'], "typewriter", "tt", "FiraMono", "scaled", "lf", "true") + return fm + +def convert_fonts(document, fm, osfoption = "osf"): + " Handle font definition (LaTeX preamble -> native) " + + rpkg = re.compile(r'^\\usepackage(\[([^\]]*)\])?\{([^\}]+)\}') + rscaleopt = re.compile(r'^scaled?=(.*)') + + # Check whether we go beyond font option feature introduction + haveFontOpts = document.end_format > 580 + + i = 0 + while i < len(document.preamble): + i = find_re(document.preamble, rpkg, i+1) + if i == -1: + return + mo = rpkg.search(document.preamble[i]) + if mo == None or mo.group(2) == None: + options = [] + else: + options = mo.group(2).replace(' ', '').split(",") + pkg = mo.group(3) + o = 0 + oscale = 1 + has_osf = False + while o < len(options): + if options[o] == osfoption: + has_osf = True + del options[o] + continue + mo = rscaleopt.search(options[o]) + if mo == None: + o += 1 + continue + oscale = mo.group(1) + del options[o] + continue + + if not pkg in fm.pkginmap: + continue + # determine fontname + fn = None + if haveFontOpts: + # Try with name-option combination first + # (only one default option supported currently) + o = 0 + while o < len(options): + opt = options[o] + fn = fm.getfontname(pkg, [opt]) + if fn != None: + del options[o] + break + o += 1 + continue + if fn == None: + fn = fm.getfontname(pkg, []) + else: + fn = fm.getfontname(pkg, options) + if fn == None: + continue + del document.preamble[i] + fontinfo = fm.font2pkgmap[fn] + if fontinfo.scaletype == None: + fontscale = None + else: + fontscale = "\\font_" + fontinfo.scaletype + "_scale" + fontinfo.scaleval = oscale + if (has_osf and fontinfo.osfdef == "false") or (not has_osf and fontinfo.osfdef == "true"): + if fontinfo.osfopt == None: + options.extend(osfoption) + continue + osf = find_token(document.header, "\\font_osf false") + osftag = "\\font_osf" + if osf == -1 and fontinfo.fonttype != "math": + # Try with newer format + osftag = "\\font_" + fontinfo.fonttype + "_osf" + osf = find_token(document.header, osftag + " false") + if osf != -1: + document.header[osf] = osftag + " true" + if i > 0 and document.preamble[i-1] == "% Added by lyx2lyx": + del document.preamble[i-1] + i -= 1 + if fontscale != None: + j = find_token(document.header, fontscale, 0) + if j != -1: + val = get_value(document.header, fontscale, j) + vals = val.split() + scale = "100" + if oscale != None: + scale = "%03d" % int(float(oscale) * 100) + document.header[j] = fontscale + " " + scale + " " + vals[1] + ft = "\\font_" + fontinfo.fonttype + j = find_token(document.header, ft, 0) + if j != -1: + val = get_value(document.header, ft, j) + words = val.split() # ! splits also values like '"DejaVu Sans"' + words[0] = '"' + fn + '"' + document.header[j] = ft + ' ' + ' '.join(words) + if haveFontOpts and fontinfo.fonttype != "math": + fotag = "\\font_" + fontinfo.fonttype + "_opts" + fo = find_token(document.header, fotag) + if fo != -1: + document.header[fo] = fotag + " \"" + ",".join(options) + "\"" + else: + # Sensible place to insert tag + fo = find_token(document.header, "\\font_sf_scale") + if fo == -1: + document.warning("Malformed LyX document! Missing \\font_sf_scale") + else: + document.header.insert(fo, fotag + " \"" + ",".join(options) + "\"") + + +def revert_fonts(document, fm, fontmap, OnlyWithXOpts = False, WithXOpts = False): + " Revert native font definition to LaTeX " + # fonlist := list of fonts created from the same package + # Empty package means that the font-name is the same as the package-name + # fontmap (key = package, val += found options) will be filled + # and used later in add_preamble_fonts() to be added to user-preamble + + rfontscale = re.compile(r'^\s*(\\font_(roman|sans|typewriter|math))\s+') + rscales = re.compile(r'^\s*(\d+)\s+(\d+)') + i = 0 + while i < len(document.header): + i = find_re(document.header, rfontscale, i+1) + if (i == -1): + return True + mo = rfontscale.search(document.header[i]) + if mo == None: + continue + ft = mo.group(1) # 'roman', 'sans', 'typewriter', 'math' + val = get_value(document.header, ft, i) + words = val.split(' ') # ! splits also values like '"DejaVu Sans"' + font = words[0].strip('"') # TeX font name has no whitespace + if not font in fm.font2pkgmap: + continue + fontinfo = fm.font2pkgmap[font] + val = fontinfo.package + if not val in fontmap: + fontmap[val] = [] + x = -1 + if OnlyWithXOpts or WithXOpts: + if ft == "\\font_math": + return False + regexp = re.compile(r'^\s*(\\font_roman_opts)\s+') + if ft == "\\font_sans": + regexp = re.compile(r'^\s*(\\font_sans_opts)\s+') + elif ft == "\\font_typewriter": + regexp = re.compile(r'^\s*(\\font_typewriter_opts)\s+') + x = find_re(document.header, regexp, 0) + if x == -1 and OnlyWithXOpts: + return False + + if x != -1: + # We need to use this regex since split() does not handle quote protection + xopts = re.findall(r'[^"\s]\S*|".+?"', document.header[x]) + opts = xopts[1].strip('"').split(",") + fontmap[val].extend(opts) + del document.header[x] + words[0] = '"default"' + document.header[i] = ft + ' ' + ' '.join(words) + if fontinfo.scaleopt != None: + xval = get_value(document.header, "\\font_" + fontinfo.scaletype + "_scale", 0) + mo = rscales.search(xval) + if mo != None: + xval1 = mo.group(1) + xval2 = mo.group(2) + if xval1 != "100": + # set correct scale option + fontmap[val].extend([fontinfo.scaleopt + "=" + format(float(xval1) / 100, '.2f')]) + if fontinfo.osfopt != None: + oldval = "true" + if fontinfo.osfdef == "true": + oldval = "false" + osf = find_token(document.header, "\\font_osf " + oldval) + if osf == -1 and ft != "\\font_math": + # Try with newer format + osftag = "\\font_roman_osf " + oldval + if ft == "\\font_sans": + osftag = "\\font_sans_osf " + oldval + elif ft == "\\font_typewriter": + osftag = "\\font_typewriter_osf " + oldval + osf = find_token(document.header, osftag) + if osf != -1: + fontmap[val].extend([fontinfo.osfopt]) + if len(fontinfo.options) > 0: + fontmap[val].extend(fontinfo.options) + return True ############################################################################### ### @@ -49,30 +389,97 @@ from lyx2lyx_tools import (put_cmd_in_ert, add_to_preamble) ### ############################################################################### +def convert_inputencoding_namechange(document): + " Rename inputencoding settings. " + i = find_token(document.header, "\\inputencoding", 0) + if i == -1: + return + s = document.header[i].replace("auto", "auto-legacy") + document.header[i] = s.replace("default", "auto-legacy-plain") + +def revert_inputencoding_namechange(document): + " Rename inputencoding settings. " + i = find_token(document.header, "\\inputencoding", 0) + if i == -1: + return + s = document.header[i].replace("auto-legacy-plain", "default") + document.header[i] = s.replace("auto-legacy", "auto") + +def convert_notoFonts(document): + " Handle Noto fonts definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fm = createFontMapping(['Noto']) + convert_fonts(document, fm) + +def revert_notoFonts(document): + " Revert native Noto font definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fontmap = dict() + fm = createFontMapping(['Noto']) + if revert_fonts(document, fm, fontmap): + add_preamble_fonts(document, fontmap) + +def convert_latexFonts(document): + " Handle DejaVu and IBMPlex fonts definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fm = createFontMapping(['DejaVu', 'IBM']) + convert_fonts(document, fm) + +def revert_latexFonts(document): + " Revert native DejaVu font definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fontmap = dict() + fm = createFontMapping(['DejaVu', 'IBM']) + if revert_fonts(document, fm, fontmap): + add_preamble_fonts(document, fontmap) + +def convert_AdobeFonts(document): + " Handle Adobe Source fonts definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fm = createFontMapping(['Adobe']) + convert_fonts(document, fm) + +def revert_AdobeFonts(document): + " Revert Adobe Source font definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fontmap = dict() + fm = createFontMapping(['Adobe']) + if revert_fonts(document, fm, fontmap): + add_preamble_fonts(document, fontmap) + def removeFrontMatterStyles(document): - " Remove styles Begin/EndFromatter" + " Remove styles Begin/EndFrontmatter" layouts = ['BeginFrontmatter', 'EndFrontmatter'] - for layout in layouts: - i = 0 - while True: - i = find_token(document.body, '\\begin_layout ' + layout, i) - if i == -1: - break - j = find_end_of_layout(document.body, i) - if j == -1: - document.warning("Malformed LyX document: Can't find end of layout at line %d" % i) - i += 1 - continue - while i > 0 and document.body[i-1].strip() == '': - i -= 1 - while document.body[j+1].strip() == '': - j = j + 1 - document.body[i:j+1] = [''] + tokenend = len('\\begin_layout ') + i = 0 + while True: + i = find_token_exact(document.body, '\\begin_layout ', i+1) + if i == -1: + return + layout = document.body[i][tokenend:].strip() + if layout not in layouts: + continue + j = find_end_of_layout(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of layout at line %d" % i) + continue + while document.body[j+1].strip() == '': + j += 1 + document.body[i:j+1] = [] def addFrontMatterStyles(document): " Use styles Begin/EndFrontmatter for elsarticle" + if document.textclass != "elsarticle": + return + def insertFrontmatter(prefix, line): above = line while above > 0 and document.body[above-1].strip() == '': @@ -89,48 +496,46 @@ def addFrontMatterStyles(document): '\\end_inset', '', '', '\\end_layout', ''] - if document.textclass == "elsarticle": - layouts = ['Title', 'Title footnote', 'Author', 'Author footnote', - 'Corresponding author', 'Address', 'Email', 'Abstract', 'Keywords'] - first = -1 - last = -1 - for layout in layouts: - i = 0 - while True: - i = find_token(document.body, '\\begin_layout ' + layout, i) - if i == -1: - break - k = find_end_of_layout(document.body, i) - if k == -1: - document.warning("Malformed LyX document: Can't find end of layout at line %d" % i) - i += 1; - continue - if first == -1 or i < first: - first = i - if last == -1 or last <= k: - last = k+1 - i = k+1 + layouts = ['Title', 'Title footnote', 'Author', 'Author footnote', + 'Corresponding author', 'Address', 'Email', 'Abstract', 'Keywords'] + tokenend = len('\\begin_layout ') + first = -1 + i = 0 + while True: + i = find_token_exact(document.body, '\\begin_layout ', i+1) + if i == -1: + break + layout = document.body[i][tokenend:].strip() + if layout not in layouts: + continue + k = find_end_of_layout(document.body, i) + if k == -1: + document.warning("Malformed LyX document: Can't find end of layout at line %d" % i) + continue if first == -1: - return - insertFrontmatter('End', last) - insertFrontmatter('Begin', first) + first = i + i = k + if first == -1: + return + insertFrontmatter('End', k+1) + insertFrontmatter('Begin', first) + def convert_lst_literalparam(document): " Add param literal to include inset " i = 0 while True: - i = find_token(document.body, '\\begin_inset CommandInset include', i) + i = find_token(document.body, '\\begin_inset CommandInset include', i+1) if i == -1: break j = find_end_of_inset(document.body, i) if j == -1: document.warning("Malformed LyX document: Can't find end of command inset at line %d" % i) - i += 1 continue while i < j and document.body[i].strip() != '': i += 1 - document.body.insert(i, "literal \"true\"") + document.body.insert(i, 'literal "true"') def revert_lst_literalparam(document): @@ -138,19 +543,14 @@ def revert_lst_literalparam(document): i = 0 while True: - i = find_token(document.body, '\\begin_inset CommandInset include', i) + i = find_token(document.body, '\\begin_inset CommandInset include', i+1) if i == -1: break j = find_end_of_inset(document.body, i) if j == -1: document.warning("Malformed LyX document: Can't find end of include inset at line %d" % i) - i += 1 - continue - k = find_token(document.body, 'literal', i, j) - if k == -1: - i += 1 continue - del document.body[k] + del_token(document.body, 'literal', i, j) def revert_paratype(document): @@ -162,12 +562,25 @@ def revert_paratype(document): i2 = find_token(document.header, "\\font_sans \"default\"", 0) i3 = find_token(document.header, "\\font_typewriter \"default\"", 0) j = find_token(document.header, "\\font_sans \"PTSans-TLF\"", 0) - sfval = get_value(document.header, "\\font_sf_scale", 0) - # cutoff " 100" - sfval = sfval[:-4] + + sf_scale = 100.0 + sfval = find_token(document.header, "\\font_sf_scale", 0) + if sfval == -1: + document.warning("Malformed LyX document: Missing \\font_sf_scale.") + else: + sfscale = document.header[sfval].split() + val = sfscale[1] + sfscale[1] = "100" + document.header[sfval] = " ".join(sfscale) + try: + # float() can throw + sf_scale = float(val) + except: + document.warning("Invalid font_sf_scale value: " + val) + sfoption = "" - if sfval != "100": - sfoption = "scaled=" + format(float(sfval) / 100, '.2f') + if sf_scale != "100.0": + sfoption = "scaled=" + str(sf_scale / 100.0) k = find_token(document.header, "\\font_typewriter \"PTMono-TLF\"", 0) ttval = get_value(document.header, "\\font_tt_scale", 0) # cutoff " 100" @@ -227,13 +640,12 @@ def revert_lscape(document): i = 0 while True: - i = find_token(document.body, "\\begin_inset Flex Landscape", i) + i = find_token(document.body, "\\begin_inset Flex Landscape", i+1) if i == -1: - return + break j = find_end_of_inset(document.body, i) if j == -1: document.warning("Malformed LyX document: Can't find end of Landscape inset") - i += 1 continue if document.body[i] == "\\begin_inset Flex Landscape (Floating)": @@ -245,7 +657,7 @@ def revert_lscape(document): document.body[i : i + 4] = put_cmd_in_ert("\\begin{landscape}") add_to_preamble(document, ["\\usepackage{pdflscape}"]) - # no need to reset i + document.del_module("landscape") def convert_fontenc(document): @@ -282,14 +694,11 @@ def revert_nospellcheck(document): def revert_floatpclass(document): " Remove float placement params 'document' and 'class' " - i = 0 - i = find_token(document.header, "\\float_placement class", 0) - if i != -1: - del document.header[i] + del_token(document.header, "\\float_placement class") i = 0 while True: - i = find_token(document.body, '\\begin_inset Float', i) + i = find_token(document.body, '\\begin_inset Float', i+1) if i == -1: break j = find_end_of_inset(document.body, i) @@ -298,7 +707,6 @@ def revert_floatpclass(document): k = find_token(document.body, 'placement document', i, i + 2) if k != -1: del document.body[k] - i = j continue del document.body[k] @@ -306,23 +714,18 @@ def revert_floatpclass(document): def revert_floatalignment(document): " Remove float alignment params " - i = 0 - i = find_token(document.header, "\\float_alignment", 0) - galignment = "" - if i != -1: - galignment = get_value(document.header, "\\float_alignment", i) - del document.header[i] + galignment = get_value(document.header, "\\float_alignment", delete=True) i = 0 while True: - i = find_token(document.body, '\\begin_inset Float', i) + i = find_token(document.body, '\\begin_inset Float', i+1) if i == -1: break j = find_end_of_inset(document.body, i) if j == -1: document.warning("Malformed LyX document: Can't find end of inset at line " + str(i)) - i += 1 - k = find_token(document.body, 'alignment', i, i + 4) + continue + k = find_token(document.body, 'alignment', i, i+4) if k == -1: i = j continue @@ -333,7 +736,6 @@ def revert_floatalignment(document): l = find_token(document.body, "\\begin_layout Plain Layout", i, j) if l == -1: document.warning("Can't find float layout!") - i = j continue alcmd = [] if alignment == "left": @@ -344,8 +746,7 @@ def revert_floatalignment(document): alcmd = put_cmd_in_ert("\\raggedleft{}") if len(alcmd) > 0: document.body[l+1:l+1] = alcmd - i = j - + i = j def revert_tuftecite(document): " Revert \cite commands in tufte classes " @@ -356,22 +757,21 @@ def revert_tuftecite(document): i = 0 while (True): - i = find_token(document.body, "\\begin_inset CommandInset citation", i) + i = find_token(document.body, "\\begin_inset CommandInset citation", i+1) if i == -1: break j = find_end_of_inset(document.body, i) if j == -1: document.warning("Can't find end of citation inset at line %d!!" %(i)) - i += 1 continue k = find_token(document.body, "LatexCommand", i, j) if k == -1: document.warning("Can't find LatexCommand for citation inset at line %d!" %(i)) - i = j + 1 + i = j continue cmd = get_value(document.body, "LatexCommand", k) if cmd != "cite": - i = j + 1 + i = j continue pre = get_quoted_value(document.body, "before", i, j) post = get_quoted_value(document.body, "after", i, j) @@ -389,17 +789,17 @@ def revert_tuftecite(document): res += "[]" res += "{" + key + "}" document.body[i:j+1] = put_cmd_in_ert([res]) - i = j + 1 + i = j def revert_stretchcolumn(document): " We remove the column varwidth flags or everything else will become a mess. " i = 0 while True: - i = find_token(document.body, "\\begin_inset Tabular", i) + i = find_token(document.body, "\\begin_inset Tabular", i+1) if i == -1: return - j = find_end_of_inset(document.body, i + 1) + j = find_end_of_inset(document.body, i+1) if j == -1: document.warning("Malformed LyX document: Could not find end of tabular.") continue @@ -407,7 +807,6 @@ def revert_stretchcolumn(document): if re.search('^$', document.body[k]): document.warning("Converting 'tabularx'/'xltabular' table to normal table.") document.body[k] = document.body[k].replace(' varwidth="true"', '') - i = i + 1 def revert_vcolumns(document): @@ -417,13 +816,12 @@ def revert_vcolumns(document): needarray = False try: while True: - i = find_token(document.body, "\\begin_inset Tabular", i) + i = find_token(document.body, "\\begin_inset Tabular", i+1) if i == -1: return j = find_end_of_inset(document.body, i) if j == -1: document.warning("Malformed LyX document: Could not find end of tabular.") - i += 1 continue # Collect necessary column information @@ -474,7 +872,7 @@ def revert_vcolumns(document): if vval != "": needarray = True vval += "V{\\linewidth}" - + document.body[col_line] = document.body[col_line][:-1] + " special=\"" + vval + "\">" # ERT newlines and linebreaks (since LyX < 2.4 automatically inserts parboxes # with newlines, and we do not want that) @@ -495,7 +893,7 @@ def revert_vcolumns(document): document.body[nl:nl+1] = put_cmd_in_ert("\\\\") m += 1 - i = j + 1 + i = j finally: if needarray == True: @@ -520,7 +918,7 @@ def revert_bibencoding(document): if engine in ["biblatex", "biblatex-natbib"]: biblatex = True - # Map lyx to latex encoding names + # Map lyx to latex encoding names encodings = { "utf8" : "utf8", "utf8x" : "utf8x", @@ -563,22 +961,22 @@ def revert_bibencoding(document): i = 0 bibresources = [] while (True): - i = find_token(document.body, "\\begin_inset CommandInset bibtex", i) + i = find_token(document.body, "\\begin_inset CommandInset bibtex", i+1) if i == -1: break j = find_end_of_inset(document.body, i) if j == -1: document.warning("Can't find end of bibtex inset at line %d!!" %(i)) - i += 1 continue encoding = get_quoted_value(document.body, "encoding", i, j) if not encoding: - i += 1 continue # remove encoding line k = find_token(document.body, "encoding", i, j) if k != -1: del document.body[k] + if encoding == "default": + continue # Re-find inset end line j = find_end_of_inset(document.body, i) if biblatex: @@ -599,7 +997,7 @@ def revert_bibencoding(document): document.body[j+1:j+1] = put_cmd_in_ert("\\egroup") document.body[i:i] = put_cmd_in_ert("\\bgroup\\inputencoding{" + encodings[encoding] + "}") - i = j + 1 + i = j @@ -615,27 +1013,23 @@ def convert_vcsinfo(document): } i = 0 while True: - i = find_token(document.body, "\\begin_inset Info", i) + i = find_token(document.body, "\\begin_inset Info", i+1) if i == -1: return - j = find_end_of_inset(document.body, i + 1) + j = find_end_of_inset(document.body, i+1) if j == -1: document.warning("Malformed LyX document: Could not find end of Info inset.") - i = i + 1 continue tp = find_token(document.body, 'type', i, j) tpv = get_quoted_value(document.body, "type", tp) if tpv != "buffer": - i = i + 1 continue arg = find_token(document.body, 'arg', i, j) argv = get_quoted_value(document.body, "arg", arg) if argv not in list(types.keys()): - i = i + 1 continue document.body[tp] = "type \"vcs\"" document.body[arg] = "arg \"" + types[argv] + "\"" - i = i + 1 def revert_vcsinfo(document): @@ -644,29 +1038,2548 @@ def revert_vcsinfo(document): args = ["revision", "tree-revision", "author", "time", "date" ] i = 0 while True: - i = find_token(document.body, "\\begin_inset Info", i) + i = find_token(document.body, "\\begin_inset Info", i+1) if i == -1: return - j = find_end_of_inset(document.body, i + 1) + j = find_end_of_inset(document.body, i+1) if j == -1: document.warning("Malformed LyX document: Could not find end of Info inset.") - i = i + 1 continue tp = find_token(document.body, 'type', i, j) tpv = get_quoted_value(document.body, "type", tp) if tpv != "vcs": - i = i + 1 continue arg = find_token(document.body, 'arg', i, j) argv = get_quoted_value(document.body, "arg", arg) if argv not in args: document.warning("Malformed Info inset. Invalid vcs arg.") - i = i + 1 continue document.body[tp] = "type \"buffer\"" document.body[arg] = "arg \"vcs-" + argv + "\"" - i = i + 1 +def revert_vcsinfo_rev_abbrev(document): + " Convert abbreviated revisions to regular revisions. " + + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Info", i+1) + if i == -1: + return + j = find_end_of_inset(document.body, i+1) + if j == -1: + document.warning("Malformed LyX document: Could not find end of Info inset.") + continue + tp = find_token(document.body, 'type', i, j) + tpv = get_quoted_value(document.body, "type", tp) + if tpv != "vcs": + continue + arg = find_token(document.body, 'arg', i, j) + argv = get_quoted_value(document.body, "arg", arg) + if( argv == "revision-abbrev" ): + document.body[arg] = "arg \"revision\"" + +def revert_dateinfo(document): + " Revert date info insets to static text. " + +# FIXME This currently only considers the main language and uses the system locale +# Ideally, it should honor context languages and switch the locale accordingly. + + # The date formats for each language using strftime syntax: + # long, short, loclong, locmedium, locshort + dateformats = { + "afrikaans" : ["%A, %d %B %Y", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y/%m/%d"], + "albanian" : ["%A, %d %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "american" : ["%A, %B %d, %Y", "%m/%d/%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"], + "amharic" : ["%A ፣%d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "ancientgreek" : ["%A, %d %B %Y", "%d %b %Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "arabic_arabi" : ["%A، %d %B، %Y", "%d‏/%m‏/%Y", "%d %B، %Y", "%d/%m/%Y", "%d/%m/%Y"], + "arabic_arabtex" : ["%A، %d %B، %Y", "%d‏/%m‏/%Y", "%d %B، %Y", "%d/%m/%Y", "%d/%m/%Y"], + "armenian" : ["%Y թ. %B %d, %A", "%d.%m.%y", "%d %B، %Y", "%d %b، %Y", "%d/%m/%Y"], + "asturian" : ["%A, %d %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d %b %Y", "%d/%m/%Y"], + "australian" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "austrian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "bahasa" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "bahasam" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "basque" : ["%Y(e)ko %B %d, %A", "%y/%m/%d", "%Y %B %d", "%Y %b %d", "%Y/%m/%d"], + "belarusian" : ["%A, %d %B %Y г.", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"], + "bosnian" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%Y-%m-%d"], + "brazilian" : ["%A, %d de %B de %Y", "%d/%m/%Y", "%d de %B de %Y", "%d de %b de %Y", "%d/%m/%Y"], + "breton" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"], + "british" : ["%A, %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "bulgarian" : ["%A, %d %B %Y г.", "%d.%m.%y г.", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"], + "canadian" : ["%A, %B %d, %Y", "%Y-%m-%d", "%B %d, %Y", "%d %b %Y", "%Y-%m-%d"], + "canadien" : ["%A %d %B %Y", "%y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"], + "catalan" : ["%A, %d %B de %Y", "%d/%m/%y", "%d / %B / %Y", "%d / %b / %Y", "%d/%m/%Y"], + "chinese-simplified" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y-%m-%d", "%y-%m-%d"], + "chinese-traditional" : ["%Y年%m月%d日 %A", "%Y/%m/%d", "%Y年%m月%d日", "%Y年%m月%d日", "%y年%m月%d日"], + "coptic" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"], + "croatian" : ["%A, %d. %B %Y.", "%d. %m. %Y.", "%d. %B %Y.", "%d. %b. %Y.", "%d.%m.%Y."], + "czech" : ["%A %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b. %Y", "%d.%m.%Y"], + "danish" : ["%A den %d. %B %Y", "%d/%m/%Y", "%d. %B %Y", "%d. %b %Y", "%d/%m/%Y"], + "divehi" : ["%Y %B %d, %A", "%Y-%m-%d", "%Y %B %d", "%Y %b %d", "%d/%m/%Y"], + "dutch" : ["%A %d %B %Y", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"], + "english" : ["%A, %B %d, %Y", "%m/%d/%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"], + "esperanto" : ["%A, %d %B %Y", "%d %b %Y", "la %d de %B %Y", "la %d de %b %Y", "%m/%d/%Y"], + "estonian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"], + "farsi" : ["%A %d %B %Y", "%Y/%m/%d", "%d %B %Y", "%d %b %Y", "%Y/%m/%d"], + "finnish" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "french" : ["%A %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "friulan" : ["%A %d di %B dal %Y", "%d/%m/%y", "%d di %B dal %Y", "%d di %b dal %Y", "%d/%m/%Y"], + "galician" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d de %b de %Y", "%d/%m/%Y"], + "georgian" : ["%A, %d %B, %Y", "%d.%m.%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"], + "german" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "german-ch" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "german-ch-old" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "greek" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "hebrew" : ["%A, %d ב%B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "hindi" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"], + "icelandic" : ["%A, %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "interlingua" : ["%Y %B %d, %A", "%Y-%m-%d", "le %d de %B %Y", "le %d de %b %Y", "%Y-%m-%d"], + "irish" : ["%A %d %B %Y", "%d/%m/%Y", "%d. %B %Y", "%d. %b %Y", "%d/%m/%Y"], + "italian" : ["%A %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d/%b/%Y", "%d/%m/%Y"], + "japanese" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y/%m/%d", "%y/%m/%d"], + "japanese-cjk" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y/%m/%d", "%y/%m/%d"], + "kannada" : ["%A, %B %d, %Y", "%d/%m/%y", "%d %B %Y", "%d %B %Y", "%d-%m-%Y"], + "kazakh" : ["%Y ж. %d %B, %A", "%d.%m.%y", "%d %B %Y", "%d %B %Y", "%Y-%d-%m"], + "khmer" : ["%A %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %B %Y", "%d/%m/%Y"], + "korean" : ["%Y년 %m월 %d일 %A", "%y. %m. %d.", "%Y년 %m월 %d일", "%Y. %m. %d.", "%y. %m. %d."], + "kurmanji" : ["%A, %d %B %Y", "%d %b %Y", "%d. %B %Y", "%d. %m. %Y", "%Y-%m-%d"], + "lao" : ["%A ທີ %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %B %Y", "%d/%m/%Y"], + "latin" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"], + "latvian" : ["%A, %Y. gada %d. %B", "%d.%m.%y", "%Y. gada %d. %B", "%Y. gada %d. %b", "%d.%m.%Y"], + "lithuanian" : ["%Y m. %B %d d., %A", "%Y-%m-%d", "%Y m. %B %d d.", "%Y m. %B %d d.", "%Y-%m-%d"], + "lowersorbian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"], + "macedonian" : ["%A, %d %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"], + "magyar" : ["%Y. %B %d., %A", "%Y. %m. %d.", "%Y. %B %d.", "%Y. %b %d.", "%Y.%m.%d."], + "malayalam" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"], + "marathi" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"], + "mongolian" : ["%A, %Y оны %m сарын %d", "%Y-%m-%d", "%Y оны %m сарын %d", "%d-%m-%Y", "%d-%m-%Y"], + "naustrian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "newzealand" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "ngerman" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "norsk" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "nynorsk" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "occitan" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "piedmontese" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"], + "polish" : ["%A, %d %B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"], + "polutonikogreek" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "portuguese" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d de %b de %Y", "%Y/%m/%d"], + "romanian" : ["%A, %d %B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"], + "romansh" : ["%A, ils %d da %B %Y", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"], + "russian" : ["%A, %d %B %Y г.", "%d.%m.%Y", "%d %B %Y г.", "%d %b %Y г.", "%d.%m.%Y"], + "samin" : ["%Y %B %d, %A", "%Y-%m-%d", "%B %d. b. %Y", "%b %d. b. %Y", "%d.%m.%Y"], + "sanskrit" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"], + "scottish" : ["%A, %dmh %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "serbian" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "serbian-latin" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "slovak" : ["%A, %d. %B %Y", "%d. %m. %Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "slovene" : ["%A, %d. %B %Y", "%d. %m. %y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"], + "spanish" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B %de %Y", "%d %b %Y", "%d/%m/%Y"], + "spanish-mexico" : ["%A, %d de %B %de %Y", "%d/%m/%y", "%d de %B de %Y", "%d %b %Y", "%d/%m/%Y"], + "swedish" : ["%A %d %B %Y", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"], + "syriac" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "tamil" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"], + "telugu" : ["%d, %B %Y, %A", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"], + "thai" : ["%Aที่ %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + "tibetan" : ["%Y %Bའི་ཚེས་%d, %A", "%Y-%m-%d", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"], + "turkish" : ["%d %B %Y %A", "%d.%m.%Y", "%d %B %Y", "%d.%b.%Y", "%d.%m.%Y"], + "turkmen" : ["%d %B %Y %A", "%d.%m.%Y", "%Y ý. %B %d", "%d.%m.%Y ý.", "%d.%m.%y ý."], + "ukrainian" : ["%A, %d %B %Y р.", "%d.%m.%y", "%d %B %Y", "%d %m %Y", "%d.%m.%Y"], + "uppersorbian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"], + "urdu" : ["%A، %d %B، %Y", "%d/%m/%y", "%d %B, %Y", "%d %b %Y", "%d/%m/%Y"], + "vietnamese" : ["%A, %d %B, %Y", "%d/%m/%Y", "%d tháng %B %Y", "%d-%m-%Y", "%d/%m/%Y"], + "welsh" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"], + } + + types = ["date", "fixdate", "moddate" ] + lang = get_value(document.header, "\\language") + if lang == "": + document.warning("Malformed LyX document! No \\language header found!") + return + + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Info", i+1) + if i == -1: + return + j = find_end_of_inset(document.body, i+1) + if j == -1: + document.warning("Malformed LyX document: Could not find end of Info inset.") + continue + tp = find_token(document.body, 'type', i, j) + tpv = get_quoted_value(document.body, "type", tp) + if tpv not in types: + continue + arg = find_token(document.body, 'arg', i, j) + argv = get_quoted_value(document.body, "arg", arg) + isodate = "" + dte = date.today() + if tpv == "fixdate": + datecomps = argv.split('@') + if len(datecomps) > 1: + argv = datecomps[0] + isodate = datecomps[1] + m = re.search('(\d\d\d\d)-(\d\d)-(\d\d)', isodate) + if m: + dte = date(int(m.group(1)), int(m.group(2)), int(m.group(3))) +# FIXME if we had the path to the original document (not the one in the tmp dir), +# we could use the mtime. +# elif tpv == "moddate": +# dte = date.fromtimestamp(os.path.getmtime(document.dir)) + result = "" + if argv == "ISO": + result = dte.isodate() + elif argv == "long": + result = dte.strftime(dateformats[lang][0]) + elif argv == "short": + result = dte.strftime(dateformats[lang][1]) + elif argv == "loclong": + result = dte.strftime(dateformats[lang][2]) + elif argv == "locmedium": + result = dte.strftime(dateformats[lang][3]) + elif argv == "locshort": + result = dte.strftime(dateformats[lang][4]) + else: + fmt = argv.replace("MMMM", "%b").replace("MMM", "%b").replace("MM", "%m").replace("M", "%m") + fmt = fmt.replace("yyyy", "%Y").replace("yy", "%y") + fmt = fmt.replace("dddd", "%A").replace("ddd", "%a").replace("dd", "%d") + fmt = re.sub('[^\'%]d', '%d', fmt) + fmt = fmt.replace("'", "") + result = dte.strftime(fmt) + if sys.version_info < (3,0): + # In Python 2, datetime module works with binary strings, + # our dateformat strings are utf8-encoded: + result = result.decode('utf-8') + document.body[i : j+1] = [result] + + +def revert_timeinfo(document): + " Revert time info insets to static text. " + +# FIXME This currently only considers the main language and uses the system locale +# Ideally, it should honor context languages and switch the locale accordingly. +# Also, the time object is "naive", i.e., it does not know of timezones (%Z will +# be empty). + + # The time formats for each language using strftime syntax: + # long, short + timeformats = { + "afrikaans" : ["%H:%M:%S %Z", "%H:%M"], + "albanian" : ["%I:%M:%S %p, %Z", "%I:%M %p"], + "american" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "amharic" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "ancientgreek" : ["%H:%M:%S %Z", "%H:%M:%S"], + "arabic_arabi" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "arabic_arabtex" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "armenian" : ["%H:%M:%S %Z", "%H:%M"], + "asturian" : ["%H:%M:%S %Z", "%H:%M"], + "australian" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "austrian" : ["%H:%M:%S %Z", "%H:%M"], + "bahasa" : ["%H.%M.%S %Z", "%H.%M"], + "bahasam" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "basque" : ["%H:%M:%S (%Z)", "%H:%M"], + "belarusian" : ["%H:%M:%S, %Z", "%H:%M"], + "bosnian" : ["%H:%M:%S %Z", "%H:%M"], + "brazilian" : ["%H:%M:%S %Z", "%H:%M"], + "breton" : ["%H:%M:%S %Z", "%H:%M"], + "british" : ["%H:%M:%S %Z", "%H:%M"], + "bulgarian" : ["%H:%M:%S %Z", "%H:%M"], + "canadian" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "canadien" : ["%H:%M:%S %Z", "%H h %M"], + "catalan" : ["%H:%M:%S %Z", "%H:%M"], + "chinese-simplified" : ["%Z %p%I:%M:%S", "%p%I:%M"], + "chinese-traditional" : ["%p%I:%M:%S [%Z]", "%p%I:%M"], + "coptic" : ["%H:%M:%S %Z", "%H:%M:%S"], + "croatian" : ["%H:%M:%S (%Z)", "%H:%M"], + "czech" : ["%H:%M:%S %Z", "%H:%M"], + "danish" : ["%H.%M.%S %Z", "%H.%M"], + "divehi" : ["%H:%M:%S %Z", "%H:%M"], + "dutch" : ["%H:%M:%S %Z", "%H:%M"], + "english" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "esperanto" : ["%H:%M:%S %Z", "%H:%M:%S"], + "estonian" : ["%H:%M:%S %Z", "%H:%M"], + "farsi" : ["%H:%M:%S (%Z)", "%H:%M"], + "finnish" : ["%H.%M.%S %Z", "%H.%M"], + "french" : ["%H:%M:%S %Z", "%H:%M"], + "friulan" : ["%H:%M:%S %Z", "%H:%M"], + "galician" : ["%H:%M:%S %Z", "%H:%M"], + "georgian" : ["%H:%M:%S %Z", "%H:%M"], + "german" : ["%H:%M:%S %Z", "%H:%M"], + "german-ch" : ["%H:%M:%S %Z", "%H:%M"], + "german-ch-old" : ["%H:%M:%S %Z", "%H:%M"], + "greek" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "hebrew" : ["%H:%M:%S %Z", "%H:%M"], + "hindi" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "icelandic" : ["%H:%M:%S %Z", "%H:%M"], + "interlingua" : ["%H:%M:%S %Z", "%H:%M"], + "irish" : ["%H:%M:%S %Z", "%H:%M"], + "italian" : ["%H:%M:%S %Z", "%H:%M"], + "japanese" : ["%H時%M分%S秒 %Z", "%H:%M"], + "japanese-cjk" : ["%H時%M分%S秒 %Z", "%H:%M"], + "kannada" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "kazakh" : ["%H:%M:%S %Z", "%H:%M"], + "khmer" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "korean" : ["%p %I시%M분 %S초 %Z", "%p %I:%M"], + "kurmanji" : ["%H:%M:%S %Z", "%H:%M:%S"], + "lao" : ["%H ໂມງ%M ນາທີ %S ວິນາທີ %Z", "%H:%M"], + "latin" : ["%H:%M:%S %Z", "%H:%M:%S"], + "latvian" : ["%H:%M:%S %Z", "%H:%M"], + "lithuanian" : ["%H:%M:%S %Z", "%H:%M"], + "lowersorbian" : ["%H:%M:%S %Z", "%H:%M"], + "macedonian" : ["%H:%M:%S %Z", "%H:%M"], + "magyar" : ["%H:%M:%S %Z", "%H:%M"], + "malayalam" : ["%p %I:%M:%S %Z", "%p %I:%M"], + "marathi" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "mongolian" : ["%H:%M:%S %Z", "%H:%M"], + "naustrian" : ["%H:%M:%S %Z", "%H:%M"], + "newzealand" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "ngerman" : ["%H:%M:%S %Z", "%H:%M"], + "norsk" : ["%H:%M:%S %Z", "%H:%M"], + "nynorsk" : ["kl. %H:%M:%S %Z", "%H:%M"], + "occitan" : ["%H:%M:%S %Z", "%H:%M"], + "piedmontese" : ["%H:%M:%S %Z", "%H:%M:%S"], + "polish" : ["%H:%M:%S %Z", "%H:%M"], + "polutonikogreek" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "portuguese" : ["%H:%M:%S %Z", "%H:%M"], + "romanian" : ["%H:%M:%S %Z", "%H:%M"], + "romansh" : ["%H:%M:%S %Z", "%H:%M"], + "russian" : ["%H:%M:%S %Z", "%H:%M"], + "samin" : ["%H:%M:%S %Z", "%H:%M"], + "sanskrit" : ["%H:%M:%S %Z", "%H:%M"], + "scottish" : ["%H:%M:%S %Z", "%H:%M"], + "serbian" : ["%H:%M:%S %Z", "%H:%M"], + "serbian-latin" : ["%H:%M:%S %Z", "%H:%M"], + "slovak" : ["%H:%M:%S %Z", "%H:%M"], + "slovene" : ["%H:%M:%S %Z", "%H:%M"], + "spanish" : ["%H:%M:%S (%Z)", "%H:%M"], + "spanish-mexico" : ["%H:%M:%S %Z", "%H:%M"], + "swedish" : ["kl. %H:%M:%S %Z", "%H:%M"], + "syriac" : ["%H:%M:%S %Z", "%H:%M"], + "tamil" : ["%p %I:%M:%S %Z", "%p %I:%M"], + "telugu" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "thai" : ["%H นาฬิกา %M นาที %S วินาที %Z", "%H:%M"], + "tibetan" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "turkish" : ["%H:%M:%S %Z", "%H:%M"], + "turkmen" : ["%H:%M:%S %Z", "%H:%M"], + "ukrainian" : ["%H:%M:%S %Z", "%H:%M"], + "uppersorbian" : ["%H:%M:%S %Z", "%H:%M hodź."], + "urdu" : ["%I:%M:%S %p %Z", "%I:%M %p"], + "vietnamese" : ["%H:%M:%S %Z", "%H:%M"], + "welsh" : ["%H:%M:%S %Z", "%H:%M"] + } + + types = ["time", "fixtime", "modtime" ] + i = 0 + i = find_token(document.header, "\\language", 0) + if i == -1: + # this should not happen + document.warning("Malformed LyX document! No \\language header found!") + return + lang = get_value(document.header, "\\language", i) + + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Info", i+1) + if i == -1: + return + j = find_end_of_inset(document.body, i+1) + if j == -1: + document.warning("Malformed LyX document: Could not find end of Info inset.") + continue + tp = find_token(document.body, 'type', i, j) + tpv = get_quoted_value(document.body, "type", tp) + if tpv not in types: + continue + arg = find_token(document.body, 'arg', i, j) + argv = get_quoted_value(document.body, "arg", arg) + isotime = "" + dtme = datetime.now() + tme = dtme.time() + if tpv == "fixtime": + timecomps = argv.split('@') + if len(timecomps) > 1: + argv = timecomps[0] + isotime = timecomps[1] + m = re.search('(\d\d):(\d\d):(\d\d)', isotime) + if m: + tme = time(int(m.group(1)), int(m.group(2)), int(m.group(3))) + else: + m = re.search('(\d\d):(\d\d)', isotime) + if m: + tme = time(int(m.group(1)), int(m.group(2))) +# FIXME if we had the path to the original document (not the one in the tmp dir), +# we could use the mtime. +# elif tpv == "moddate": +# dte = date.fromtimestamp(os.path.getmtime(document.dir)) + result = "" + if argv == "ISO": + result = tme.isoformat() + elif argv == "long": + result = tme.strftime(timeformats[lang][0]) + elif argv == "short": + result = tme.strftime(timeformats[lang][1]) + else: + fmt = argv.replace("HH", "%H").replace("H", "%H").replace("hh", "%I").replace("h", "%I") + fmt = fmt.replace("mm", "%M").replace("m", "%M").replace("ss", "%S").replace("s", "%S") + fmt = fmt.replace("zzz", "%f").replace("z", "%f").replace("t", "%Z") + fmt = fmt.replace("AP", "%p").replace("ap", "%p").replace("A", "%p").replace("a", "%p") + fmt = fmt.replace("'", "") + result = dte.strftime(fmt) + document.body[i : j+1] = result + + +def revert_namenoextinfo(document): + " Merge buffer Info inset type name-noext to name. " + + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Info", i+1) + if i == -1: + return + j = find_end_of_inset(document.body, i+1) + if j == -1: + document.warning("Malformed LyX document: Could not find end of Info inset.") + continue + tp = find_token(document.body, 'type', i, j) + tpv = get_quoted_value(document.body, "type", tp) + if tpv != "buffer": + continue + arg = find_token(document.body, 'arg', i, j) + argv = get_quoted_value(document.body, "arg", arg) + if argv != "name-noext": + continue + document.body[arg] = "arg \"name\"" + + +def revert_l7ninfo(document): + " Revert l7n Info inset to text. " + + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Info", i+1) + if i == -1: + return + j = find_end_of_inset(document.body, i+1) + if j == -1: + document.warning("Malformed LyX document: Could not find end of Info inset.") + continue + tp = find_token(document.body, 'type', i, j) + tpv = get_quoted_value(document.body, "type", tp) + if tpv != "l7n": + continue + arg = find_token(document.body, 'arg', i, j) + argv = get_quoted_value(document.body, "arg", arg) + # remove trailing colons, menu accelerator (|...) and qt accelerator (&), while keeping literal " & " + argv = argv.rstrip(':').split('|')[0].replace(" & ", "").replace("&", "").replace("", " & ") + document.body[i : j+1] = argv + + +def revert_listpargs(document): + " Reverts listpreamble arguments to TeX-code " + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Argument listpreamble:", i+1) + if i == -1: + return + j = find_end_of_inset(document.body, i) + # Find containing paragraph layout + parent = get_containing_layout(document.body, i) + if parent == False: + document.warning("Malformed LyX document: Can't find parent paragraph layout") + continue + parbeg = parent[3] + beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i) + endPlain = find_end_of_layout(document.body, beginPlain) + content = document.body[beginPlain + 1 : endPlain] + del document.body[i:j+1] + subst = ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Plain Layout", + "{"] + content + ["}", "\\end_layout", "", "\\end_inset", ""] + document.body[parbeg : parbeg] = subst + + +def revert_lformatinfo(document): + " Revert layout format Info inset to text. " + + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Info", i+1) + if i == -1: + return + j = find_end_of_inset(document.body, i+1) + if j == -1: + document.warning("Malformed LyX document: Could not find end of Info inset.") + continue + tp = find_token(document.body, 'type', i, j) + tpv = get_quoted_value(document.body, "type", tp) + if tpv != "lyxinfo": + continue + arg = find_token(document.body, 'arg', i, j) + argv = get_quoted_value(document.body, "arg", arg) + if argv != "layoutformat": + continue + # hardcoded for now + document.body[i : j+1] = "69" + + +def convert_hebrew_parentheses(document): + """ Swap opening/closing parentheses in Hebrew text. + + Up to LyX 2.4, "(" was used as closing parenthesis and + ")" as opening parenthesis for Hebrew in the LyX source. + """ + # print("convert hebrew parentheses") + current_languages = [document.language] + for i, line in enumerate(document.body): + if line.startswith('\\lang '): + current_languages[-1] = line.lstrip('\\lang ') + elif line.startswith('\\begin_layout'): + current_languages.append(current_languages[-1]) + # print (line, current_languages[-1]) + elif line.startswith('\\end_layout'): + current_languages.pop() + elif current_languages[-1] == 'hebrew' and not line.startswith('\\'): + document.body[i] = line.replace('(','\x00').replace(')','(').replace('\x00',')') + + +def revert_hebrew_parentheses(document): + " Store parentheses in Hebrew text reversed" + # This only exists to keep the convert/revert naming convention + convert_hebrew_parentheses(document) + + +def revert_malayalam(document): + " Set the document language to English but assure Malayalam output " + + revert_language(document, "malayalam", "", "malayalam") + + +def revert_soul(document): + " Revert soul module flex insets to ERT " + + flexes = ["Spaceletters", "Strikethrough", "Underline", "Highlight", "Capitalize"] + + for flex in flexes: + i = find_token(document.body, "\\begin_inset Flex %s" % flex, 0) + if i != -1: + add_to_preamble(document, ["\\usepackage{soul}"]) + break + i = find_token(document.body, "\\begin_inset Flex Highlight", 0) + if i != -1: + add_to_preamble(document, ["\\usepackage{color}"]) + + revert_flex_inset(document.body, "Spaceletters", "\\so") + revert_flex_inset(document.body, "Strikethrough", "\\st") + revert_flex_inset(document.body, "Underline", "\\ul") + revert_flex_inset(document.body, "Highlight", "\\hl") + revert_flex_inset(document.body, "Capitalize", "\\caps") + + +def revert_tablestyle(document): + " Remove tablestyle params " + + i = 0 + i = find_token(document.header, "\\tablestyle") + if i != -1: + del document.header[i] + + +def revert_bibfileencodings(document): + " Revert individual Biblatex bibliography encodings " + + # Get cite engine + engine = "basic" + i = find_token(document.header, "\\cite_engine", 0) + if i == -1: + document.warning("Malformed document! Missing \\cite_engine") + else: + engine = get_value(document.header, "\\cite_engine", i) + + # Check if biblatex + biblatex = False + if engine in ["biblatex", "biblatex-natbib"]: + biblatex = True + + # Map lyx to latex encoding names + encodings = { + "utf8" : "utf8", + "utf8x" : "utf8x", + "armscii8" : "armscii8", + "iso8859-1" : "latin1", + "iso8859-2" : "latin2", + "iso8859-3" : "latin3", + "iso8859-4" : "latin4", + "iso8859-5" : "iso88595", + "iso8859-6" : "8859-6", + "iso8859-7" : "iso-8859-7", + "iso8859-8" : "8859-8", + "iso8859-9" : "latin5", + "iso8859-13" : "latin7", + "iso8859-15" : "latin9", + "iso8859-16" : "latin10", + "applemac" : "applemac", + "cp437" : "cp437", + "cp437de" : "cp437de", + "cp850" : "cp850", + "cp852" : "cp852", + "cp855" : "cp855", + "cp858" : "cp858", + "cp862" : "cp862", + "cp865" : "cp865", + "cp866" : "cp866", + "cp1250" : "cp1250", + "cp1251" : "cp1251", + "cp1252" : "cp1252", + "cp1255" : "cp1255", + "cp1256" : "cp1256", + "cp1257" : "cp1257", + "koi8-r" : "koi8-r", + "koi8-u" : "koi8-u", + "pt154" : "pt154", + "utf8-platex" : "utf8", + "ascii" : "ascii" + } + + i = 0 + bibresources = [] + while (True): + i = find_token(document.body, "\\begin_inset CommandInset bibtex", i+1) + if i == -1: + break + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Can't find end of bibtex inset at line %d!!" %(i)) + continue + encodings = get_quoted_value(document.body, "file_encodings", i, j) + if not encodings: + i = j + continue + bibfiles = get_quoted_value(document.body, "bibfiles", i, j).split(",") + opts = get_quoted_value(document.body, "biblatexopts", i, j) + if len(bibfiles) == 0: + document.warning("Bibtex inset at line %d does not have a bibfile!" %(i)) + # remove encoding line + k = find_token(document.body, "file_encodings", i, j) + if k != -1: + del document.body[k] + # Re-find inset end line + j = find_end_of_inset(document.body, i) + if biblatex: + enclist = encodings.split("\t") + encmap = dict() + for pp in enclist: + ppp = pp.split(" ", 1) + encmap[ppp[0]] = ppp[1] + for bib in bibfiles: + pr = "\\addbibresource" + if bib in encmap.keys(): + pr += "[bibencoding=" + encmap[bib] + "]" + pr += "{" + bib + "}" + add_to_preamble(document, [pr]) + # Insert ERT \\printbibliography and wrap bibtex inset to a Note + pcmd = "printbibliography" + if opts: + pcmd += "[" + opts + "]" + repl = ["\\begin_inset ERT", "status open", "", "\\begin_layout Plain Layout",\ + "", "", "\\backslash", pcmd, "\\end_layout", "", "\\end_inset", "", "",\ + "\\end_layout", "", "\\begin_layout Standard", "\\begin_inset Note Note",\ + "status open", "", "\\begin_layout Plain Layout" ] + repl += document.body[i:j+1] + repl += ["", "\\end_layout", "", "\\end_inset", "", ""] + document.body[i:j+1] = repl + j += 27 + + i = j + + +def revert_cmidruletrimming(document): + " Remove \\cmidrule trimming " + + # FIXME: Revert to TeX code? + i = 0 + while True: + # first, let's find out if we need to do anything + i = find_token(document.body, ' -1: + usepkg = re.match(r"\\usepackage(.*){lineno}", document.preamble[i-1]) + if usepkg: + use_lineno = 1 + options = usepkg.group(1).strip("[]") + del(document.preamble[i-1:i+1]) + del_token(document.preamble, "% Added by lyx2lyx", i-2, i-1) + + k = find_token(document.header, "\\index ") + if options == "": + document.header[k:k] = ["\\use_lineno %d" % use_lineno] + else: + document.header[k:k] = ["\\use_lineno %d" % use_lineno, + "\\lineno_options %s" % options] + + +def revert_new_languages(document): + """Emulate support for Azerbaijani, Bengali, Church Slavonic, Korean, + and Russian (Petrine orthography).""" + + # lyxname: (babelname, polyglossianame) + new_languages = {"azerbaijani": ("azerbaijani", ""), + "bengali": ("", "bengali"), + "churchslavonic": ("", "churchslavonic"), + "oldrussian": ("", "russian"), + "korean": ("", "korean"), + } + used_languages = set() + if document.language in new_languages: + used_languages.add(document.language) + i = 0 + while True: + i = find_token(document.body, "\\lang", i+1) + if i == -1: + break + if document.body[i][6:].strip() in new_languages: + used_languages.add(document.language) + + # Korean is already supported via CJK, so leave as-is for Babel + if ("korean" in used_languages + and get_bool_value(document.header, "\\use_non_tex_fonts") + and get_value(document.header, "\\language_package") in ("default", "auto")): + revert_language(document, "korean", "", "korean") + used_languages.discard("korean") + + for lang in used_languages: + revert(lang, *new_languages[lang]) + + +gloss_inset_def = [ + r'### Inserted by lyx2lyx (deprecated ling glosses) ###', + r'InsetLayout Flex:Glosse', + r' LyXType custom', + r' LabelString "Gloss (old version)"', + r' MenuString "Gloss (old version)"', + r' LatexType environment', + r' LatexName linggloss', + r' Decoration minimalistic', + r' LabelFont', + r' Size Small', + r' EndFont', + r' MultiPar true', + r' CustomPars false', + r' ForcePlain true', + r' ParbreakIsNewline true', + r' FreeSpacing true', + r' Requires covington', + r' Preamble', + r' \def\glosstr{}', + r' \@ifundefined{linggloss}{%', + r' \newenvironment{linggloss}[2][]{', + r' \def\glosstr{\glt #1}%', + r' \gll #2}', + r' {\glosstr\glend}}{}', + r' EndPreamble', + r' InToc true', + r' ResetsFont true', + r' Argument 1', + r' Decoration conglomerate', + r' LabelString "Translation"', + r' MenuString "Glosse Translation|s"', + r' Tooltip "Add a translation for the glosse"', + r' EndArgument', + r'End' +] + +glosss_inset_def = [ + r'### Inserted by lyx2lyx (deprecated ling glosses) ###', + r'InsetLayout Flex:Tri-Glosse', + r' LyXType custom', + r' LabelString "Tri-Gloss (old version)"', + r' MenuString "Tri-Gloss (old version)"', + r' LatexType environment', + r' LatexName lingglosss', + r' Decoration minimalistic', + r' LabelFont', + r' Size Small', + r' EndFont', + r' MultiPar true', + r' CustomPars false', + r' ForcePlain true', + r' ParbreakIsNewline true', + r' FreeSpacing true', + r' InToc true', + r' Requires covington', + r' Preamble', + r' \def\glosstr{}', + r' \@ifundefined{lingglosss}{%', + r' \newenvironment{lingglosss}[2][]{', + r' \def\glosstr{\glt #1}%', + r' \glll #2}', + r' {\glosstr\glend}}{}', + r' EndPreamble', + r' ResetsFont true', + r' Argument 1', + r' Decoration conglomerate', + r' LabelString "Translation"', + r' MenuString "Glosse Translation|s"', + r' Tooltip "Add a translation for the glosse"', + r' EndArgument', + r'End' +] + +def convert_linggloss(document): + " Move old ling glosses to local layout " + if find_token(document.body, '\\begin_inset Flex Glosse', 0) != -1: + document.append_local_layout(gloss_inset_def) + if find_token(document.body, '\\begin_inset Flex Tri-Glosse', 0) != -1: + document.append_local_layout(glosss_inset_def) + +def revert_linggloss(document): + " Revert to old ling gloss definitions " + if not "linguistics" in document.get_module_list(): + return + document.del_local_layout(gloss_inset_def) + document.del_local_layout(glosss_inset_def) + + cov_req = False + glosses = ["\\begin_inset Flex Interlinear Gloss (2 Lines)", "\\begin_inset Flex Interlinear Gloss (3 Lines)"] + for glosse in glosses: + i = 0 + while True: + i = find_token(document.body, glosse, i+1) + if i == -1: + break + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of Gloss inset") + continue + + arg = find_token(document.body, "\\begin_inset Argument 1", i, j) + endarg = find_end_of_inset(document.body, arg) + optargcontent = [] + if arg != -1: + argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg) + if argbeginPlain == -1: + document.warning("Malformed LyX document: Can't find optarg plain Layout") + continue + argendPlain = find_end_of_inset(document.body, argbeginPlain) + optargcontent = document.body[argbeginPlain + 1 : argendPlain - 2] + + # remove Arg insets and paragraph, if it only contains this inset + if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3: + del document.body[arg - 1 : endarg + 4] + else: + del document.body[arg : endarg + 1] + + arg = find_token(document.body, "\\begin_inset Argument post:1", i, j) + endarg = find_end_of_inset(document.body, arg) + marg1content = [] + if arg != -1: + argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg) + if argbeginPlain == -1: + document.warning("Malformed LyX document: Can't find arg 1 plain Layout") + continue + argendPlain = find_end_of_inset(document.body, argbeginPlain) + marg1content = document.body[argbeginPlain + 1 : argendPlain - 2] + + # remove Arg insets and paragraph, if it only contains this inset + if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3: + del document.body[arg - 1 : endarg + 4] + else: + del document.body[arg : endarg + 1] + + arg = find_token(document.body, "\\begin_inset Argument post:2", i, j) + endarg = find_end_of_inset(document.body, arg) + marg2content = [] + if arg != -1: + argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg) + if argbeginPlain == -1: + document.warning("Malformed LyX document: Can't find arg 2 plain Layout") + continue + argendPlain = find_end_of_inset(document.body, argbeginPlain) + marg2content = document.body[argbeginPlain + 1 : argendPlain - 2] + + # remove Arg insets and paragraph, if it only contains this inset + if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3: + del document.body[arg - 1 : endarg + 4] + else: + del document.body[arg : endarg + 1] + + arg = find_token(document.body, "\\begin_inset Argument post:3", i, j) + endarg = find_end_of_inset(document.body, arg) + marg3content = [] + if arg != -1: + argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg) + if argbeginPlain == -1: + document.warning("Malformed LyX document: Can't find arg 3 plain Layout") + continue + argendPlain = find_end_of_inset(document.body, argbeginPlain) + marg3content = document.body[argbeginPlain + 1 : argendPlain - 2] + + # remove Arg insets and paragraph, if it only contains this inset + if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3: + del document.body[arg - 1 : endarg + 4] + else: + del document.body[arg : endarg + 1] + + cmd = "\\digloss" + if glosse == "\\begin_inset Flex Interlinear Gloss (3 Lines)": + cmd = "\\trigloss" + + beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i) + endInset = find_end_of_inset(document.body, i) + endPlain = find_end_of_layout(document.body, beginPlain) + precontent = put_cmd_in_ert(cmd) + if len(optargcontent) > 0: + precontent += put_cmd_in_ert("[") + optargcontent + put_cmd_in_ert("]") + precontent += put_cmd_in_ert("{") + + postcontent = put_cmd_in_ert("}{") + marg1content + put_cmd_in_ert("}{") + marg2content + if cmd == "\\trigloss": + postcontent += put_cmd_in_ert("}{") + marg3content + postcontent += put_cmd_in_ert("}") + + document.body[endPlain:endInset + 1] = postcontent + document.body[beginPlain + 1:beginPlain] = precontent + del document.body[i : beginPlain + 1] + if not cov_req: + document.append_local_layout("Requires covington") + cov_req = True + i = beginPlain + + +def revert_subexarg(document): + " Revert linguistic subexamples with argument to ERT " + + if not "linguistics" in document.get_module_list(): + return + + cov_req = False + i = 0 + while True: + i = find_token(document.body, "\\begin_layout Subexample", i+1) + if i == -1: + break + j = find_end_of_layout(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of Subexample layout") + continue + while True: + # check for consecutive layouts + k = find_token(document.body, "\\begin_layout", j) + if k == -1 or document.body[k] != "\\begin_layout Subexample": + break + j = find_end_of_layout(document.body, k) + if j == -1: + document.warning("Malformed LyX document: Can't find end of Subexample layout") + continue + + arg = find_token(document.body, "\\begin_inset Argument 1", i, j) + if arg == -1: + continue + + endarg = find_end_of_inset(document.body, arg) + optargcontent = "" + argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg) + if argbeginPlain == -1: + document.warning("Malformed LyX document: Can't find optarg plain Layout") + continue + argendPlain = find_end_of_inset(document.body, argbeginPlain) + optargcontent = lyx2latex(document, document.body[argbeginPlain + 1 : argendPlain - 2]) + + # remove Arg insets and paragraph, if it only contains this inset + if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3: + del document.body[arg - 1 : endarg + 4] + else: + del document.body[arg : endarg + 1] + + cmd = put_cmd_in_ert("\\begin{subexamples}[" + optargcontent + "]") + + # re-find end of layout + j = find_end_of_layout(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of Subexample layout") + continue + while True: + # check for consecutive layouts + k = find_token(document.body, "\\begin_layout", j) + if k == -1 or document.body[k] != "\\begin_layout Subexample": + break + document.body[k : k + 1] = ["\\begin_layout Standard"] + put_cmd_in_ert("\\item ") + j = find_end_of_layout(document.body, k) + if j == -1: + document.warning("Malformed LyX document: Can't find end of Subexample layout") + continue + + endev = put_cmd_in_ert("\\end{subexamples}") + + document.body[j : j] = ["\\end_layout", "", "\\begin_layout Standard"] + endev + document.body[i : i + 1] = ["\\begin_layout Standard"] + cmd \ + + ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\item ") + if not cov_req: + document.append_local_layout("Requires covington") + cov_req = True + + +def revert_drs(document): + " Revert DRS insets (linguistics) to ERT " + + if not "linguistics" in document.get_module_list(): + return + + cov_req = False + drses = ["\\begin_inset Flex DRS", "\\begin_inset Flex DRS*", + "\\begin_inset Flex IfThen-DRS", "\\begin_inset Flex Cond-DRS", + "\\begin_inset Flex QDRS", "\\begin_inset Flex NegDRS", + "\\begin_inset Flex SDRS"] + for drs in drses: + i = 0 + while True: + i = find_token(document.body, drs, i+1) + if i == -1: + break + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of DRS inset") + continue + + # Check for arguments + arg = find_token(document.body, "\\begin_inset Argument 1", i, j) + endarg = find_end_of_inset(document.body, arg) + prearg1content = [] + if arg != -1: + argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg) + if argbeginPlain == -1: + document.warning("Malformed LyX document: Can't find Argument 1 plain Layout") + continue + argendPlain = find_end_of_inset(document.body, argbeginPlain) + prearg1content = document.body[argbeginPlain + 1 : argendPlain - 2] + + # remove Arg insets and paragraph, if it only contains this inset + if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3: + del document.body[arg - 1 : endarg + 4] + else: + del document.body[arg : endarg + 1] + + # re-find inset end + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of DRS inset") + continue + + arg = find_token(document.body, "\\begin_inset Argument 2", i, j) + endarg = find_end_of_inset(document.body, arg) + prearg2content = [] + if arg != -1: + argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg) + if argbeginPlain == -1: + document.warning("Malformed LyX document: Can't find Argument 2 plain Layout") + continue + argendPlain = find_end_of_inset(document.body, argbeginPlain) + prearg2content = document.body[argbeginPlain + 1 : argendPlain - 2] + + # remove Arg insets and paragraph, if it only contains this inset + if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3: + del document.body[arg - 1 : endarg + 4] + else: + del document.body[arg : endarg + 1] + + # re-find inset end + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of DRS inset") + continue + + arg = find_token(document.body, "\\begin_inset Argument post:1", i, j) + endarg = find_end_of_inset(document.body, arg) + postarg1content = [] + if arg != -1: + argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg) + if argbeginPlain == -1: + document.warning("Malformed LyX document: Can't find Argument post:1 plain Layout") + continue + argendPlain = find_end_of_inset(document.body, argbeginPlain) + postarg1content = document.body[argbeginPlain + 1 : argendPlain - 2] + + # remove Arg insets and paragraph, if it only contains this inset + if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3: + del document.body[arg - 1 : endarg + 4] + else: + del document.body[arg : endarg + 1] + + # re-find inset end + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of DRS inset") + continue + + arg = find_token(document.body, "\\begin_inset Argument post:2", i, j) + endarg = find_end_of_inset(document.body, arg) + postarg2content = [] + if arg != -1: + argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg) + if argbeginPlain == -1: + document.warning("Malformed LyX document: Can't find Argument post:2 plain Layout") + continue + argendPlain = find_end_of_inset(document.body, argbeginPlain) + postarg2content = document.body[argbeginPlain + 1 : argendPlain - 2] + + # remove Arg insets and paragraph, if it only contains this inset + if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3: + del document.body[arg - 1 : endarg + 4] + else: + del document.body[arg : endarg + 1] + + # re-find inset end + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of DRS inset") + continue + + arg = find_token(document.body, "\\begin_inset Argument post:3", i, j) + endarg = find_end_of_inset(document.body, arg) + postarg3content = [] + if arg != -1: + argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg) + if argbeginPlain == -1: + document.warning("Malformed LyX document: Can't find Argument post:3 plain Layout") + continue + argendPlain = find_end_of_inset(document.body, argbeginPlain) + postarg3content = document.body[argbeginPlain + 1 : argendPlain - 2] + + # remove Arg insets and paragraph, if it only contains this inset + if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3: + del document.body[arg - 1 : endarg + 4] + else: + del document.body[arg : endarg + 1] + + # re-find inset end + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of DRS inset") + continue + + arg = find_token(document.body, "\\begin_inset Argument post:4", i, j) + endarg = find_end_of_inset(document.body, arg) + postarg4content = [] + if arg != -1: + argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg) + if argbeginPlain == -1: + document.warning("Malformed LyX document: Can't find Argument post:4 plain Layout") + continue + argendPlain = find_end_of_inset(document.body, argbeginPlain) + postarg4content = document.body[argbeginPlain + 1 : argendPlain - 2] + + # remove Arg insets and paragraph, if it only contains this inset + if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3: + del document.body[arg - 1 : endarg + 4] + else: + del document.body[arg : endarg + 1] + + # The respective LaTeX command + cmd = "\\drs" + if drs == "\\begin_inset Flex DRS*": + cmd = "\\drs*" + elif drs == "\\begin_inset Flex IfThen-DRS": + cmd = "\\ifdrs" + elif drs == "\\begin_inset Flex Cond-DRS": + cmd = "\\condrs" + elif drs == "\\begin_inset Flex QDRS": + cmd = "\\qdrs" + elif drs == "\\begin_inset Flex NegDRS": + cmd = "\\negdrs" + elif drs == "\\begin_inset Flex SDRS": + cmd = "\\sdrs" + + beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i) + endInset = find_end_of_inset(document.body, i) + endPlain = find_token_backwards(document.body, "\\end_layout", endInset) + precontent = put_cmd_in_ert(cmd) + precontent += put_cmd_in_ert("{") + prearg1content + put_cmd_in_ert("}") + if drs == "\\begin_inset Flex SDRS": + precontent += put_cmd_in_ert("{") + prearg2content + put_cmd_in_ert("}") + precontent += put_cmd_in_ert("{") + + postcontent = [] + if cmd == "\\qdrs" or cmd == "\\condrs" or cmd == "\\ifdrs": + postcontent = put_cmd_in_ert("}{") + postarg1content + put_cmd_in_ert("}{") + postarg2content + put_cmd_in_ert("}") + if cmd == "\\condrs" or cmd == "\\qdrs": + postcontent += put_cmd_in_ert("{") + postarg3content + put_cmd_in_ert("}") + if cmd == "\\qdrs": + postcontent += put_cmd_in_ert("{") + postarg4content + put_cmd_in_ert("}") + else: + postcontent = put_cmd_in_ert("}") + + document.body[endPlain:endInset + 1] = postcontent + document.body[beginPlain + 1:beginPlain] = precontent + del document.body[i : beginPlain + 1] + if not cov_req: + document.append_local_layout("Provides covington 1") + add_to_preamble(document, ["\\usepackage{drs,covington}"]) + cov_req = True + i = beginPlain + + + +def revert_babelfont(document): + " Reverts the use of \\babelfont to user preamble " + + i = find_token(document.header, '\\use_non_tex_fonts', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\use_non_tex_fonts.") + return + if not str2bool(get_value(document.header, "\\use_non_tex_fonts", i)): + return + i = find_token(document.header, '\\language_package', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\language_package.") + return + if get_value(document.header, "\\language_package", 0) != "babel": + return + + # check font settings + # defaults + roman = sans = typew = "default" + osf = False + sf_scale = tt_scale = 100.0 + + j = find_token(document.header, "\\font_roman", 0) + if j == -1: + document.warning("Malformed LyX document: Missing \\font_roman.") + else: + # We need to use this regex since split() does not handle quote protection + romanfont = re.findall(r'[^"\s]\S*|".+?"', document.header[j]) + roman = romanfont[2].strip('"') + romanfont[2] = '"default"' + document.header[j] = " ".join(romanfont) + + j = find_token(document.header, "\\font_sans", 0) + if j == -1: + document.warning("Malformed LyX document: Missing \\font_sans.") + else: + # We need to use this regex since split() does not handle quote protection + sansfont = re.findall(r'[^"\s]\S*|".+?"', document.header[j]) + sans = sansfont[2].strip('"') + sansfont[2] = '"default"' + document.header[j] = " ".join(sansfont) + + j = find_token(document.header, "\\font_typewriter", 0) + if j == -1: + document.warning("Malformed LyX document: Missing \\font_typewriter.") + else: + # We need to use this regex since split() does not handle quote protection + ttfont = re.findall(r'[^"\s]\S*|".+?"', document.header[j]) + typew = ttfont[2].strip('"') + ttfont[2] = '"default"' + document.header[j] = " ".join(ttfont) + + i = find_token(document.header, "\\font_osf", 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_osf.") + else: + osf = str2bool(get_value(document.header, "\\font_osf", i)) + + j = find_token(document.header, "\\font_sf_scale", 0) + if j == -1: + document.warning("Malformed LyX document: Missing \\font_sf_scale.") + else: + sfscale = document.header[j].split() + val = sfscale[2] + sfscale[2] = "100" + document.header[j] = " ".join(sfscale) + try: + # float() can throw + sf_scale = float(val) + except: + document.warning("Invalid font_sf_scale value: " + val) + + j = find_token(document.header, "\\font_tt_scale", 0) + if j == -1: + document.warning("Malformed LyX document: Missing \\font_tt_scale.") + else: + ttscale = document.header[j].split() + val = ttscale[2] + ttscale[2] = "100" + document.header[j] = " ".join(ttscale) + try: + # float() can throw + tt_scale = float(val) + except: + document.warning("Invalid font_tt_scale value: " + val) + + # set preamble stuff + pretext = ['%% This document must be processed with xelatex or lualatex!'] + pretext.append('\\AtBeginDocument{%') + if roman != "default": + pretext.append('\\babelfont{rm}[Mapping=tex-text]{' + roman + '}') + if sans != "default": + sf = '\\babelfont{sf}[' + if sf_scale != 100.0: + sf += 'Scale=' + str(sf_scale / 100.0) + ',' + sf += 'Mapping=tex-text]{' + sans + '}' + pretext.append(sf) + if typew != "default": + tw = '\\babelfont{tt}' + if tt_scale != 100.0: + tw += '[Scale=' + str(tt_scale / 100.0) + ']' + tw += '{' + typew + '}' + pretext.append(tw) + if osf: + pretext.append('\\defaultfontfeatures{Numbers=OldStyle}') + pretext.append('}') + insert_to_preamble(document, pretext) + + +def revert_minionpro(document): + " Revert native MinionPro font definition (with extra options) to LaTeX " + + i = find_token(document.header, '\\use_non_tex_fonts', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\use_non_tex_fonts.") + return + if str2bool(get_value(document.header, "\\use_non_tex_fonts", i)): + return + + regexp = re.compile(r'(\\font_roman_opts)') + x = find_re(document.header, regexp, 0) + if x == -1: + return + + # We need to use this regex since split() does not handle quote protection + romanopts = re.findall(r'[^"\s]\S*|".+?"', document.header[x]) + opts = romanopts[1].strip('"') + + i = find_token(document.header, "\\font_roman", 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_roman.") + return + else: + # We need to use this regex since split() does not handle quote protection + romanfont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + roman = romanfont[1].strip('"') + if roman != "minionpro": + return + romanfont[1] = '"default"' + document.header[i] = " ".join(romanfont) + osf = False + j = find_token(document.header, "\\font_osf true", 0) + if j != -1: + osf = True + preamble = "\\usepackage[" + if osf: + document.header[j] = "\\font_osf false" + else: + preamble += "lf," + preamble += opts + preamble += "]{MinionPro}" + add_to_preamble(document, [preamble]) + del document.header[x] + + +def revert_font_opts(document): + " revert font options by outputting \\setxxxfont or \\babelfont to the preamble " + + i = find_token(document.header, '\\use_non_tex_fonts', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\use_non_tex_fonts.") + return + NonTeXFonts = str2bool(get_value(document.header, "\\use_non_tex_fonts", i)) + i = find_token(document.header, '\\language_package', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\language_package.") + return + Babel = (get_value(document.header, "\\language_package", 0) == "babel") + + # 1. Roman + regexp = re.compile(r'(\\font_roman_opts)') + i = find_re(document.header, regexp, 0) + if i != -1: + # We need to use this regex since split() does not handle quote protection + romanopts = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + opts = romanopts[1].strip('"') + del document.header[i] + if NonTeXFonts: + regexp = re.compile(r'(\\font_roman)') + i = find_re(document.header, regexp, 0) + if i != -1: + # We need to use this regex since split() does not handle quote protection + romanfont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + font = romanfont[2].strip('"') + romanfont[2] = '"default"' + document.header[i] = " ".join(romanfont) + if font != "default": + if Babel: + preamble = "\\babelfont{rm}[" + else: + preamble = "\\setmainfont[" + preamble += opts + preamble += "," + preamble += "Mapping=tex-text]{" + preamble += font + preamble += "}" + add_to_preamble(document, [preamble]) + + # 2. Sans + regexp = re.compile(r'(\\font_sans_opts)') + i = find_re(document.header, regexp, 0) + if i != -1: + scaleval = 100 + # We need to use this regex since split() does not handle quote protection + sfopts = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + opts = sfopts[1].strip('"') + del document.header[i] + if NonTeXFonts: + regexp = re.compile(r'(\\font_sf_scale)') + i = find_re(document.header, regexp, 0) + if i != -1: + scaleval = get_value(document.header, "\\font_sf_scale" , i).split()[1] + regexp = re.compile(r'(\\font_sans)') + i = find_re(document.header, regexp, 0) + if i != -1: + # We need to use this regex since split() does not handle quote protection + sffont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + font = sffont[2].strip('"') + sffont[2] = '"default"' + document.header[i] = " ".join(sffont) + if font != "default": + if Babel: + preamble = "\\babelfont{sf}[" + else: + preamble = "\\setsansfont[" + preamble += opts + preamble += "," + if scaleval != 100: + preamble += "Scale=0." + preamble += scaleval + preamble += "," + preamble += "Mapping=tex-text]{" + preamble += font + preamble += "}" + add_to_preamble(document, [preamble]) + + # 3. Typewriter + regexp = re.compile(r'(\\font_typewriter_opts)') + i = find_re(document.header, regexp, 0) + if i != -1: + scaleval = 100 + # We need to use this regex since split() does not handle quote protection + ttopts = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + opts = ttopts[1].strip('"') + del document.header[i] + if NonTeXFonts: + regexp = re.compile(r'(\\font_tt_scale)') + i = find_re(document.header, regexp, 0) + if i != -1: + scaleval = get_value(document.header, "\\font_tt_scale" , i).split()[1] + regexp = re.compile(r'(\\font_typewriter)') + i = find_re(document.header, regexp, 0) + if i != -1: + # We need to use this regex since split() does not handle quote protection + ttfont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + font = ttfont[2].strip('"') + ttfont[2] = '"default"' + document.header[i] = " ".join(ttfont) + if font != "default": + if Babel: + preamble = "\\babelfont{tt}[" + else: + preamble = "\\setmonofont[" + preamble += opts + preamble += "," + if scaleval != 100: + preamble += "Scale=0." + preamble += scaleval + preamble += "," + preamble += "Mapping=tex-text]{" + preamble += font + preamble += "}" + add_to_preamble(document, [preamble]) + + +def revert_plainNotoFonts_xopts(document): + " Revert native (straight) Noto font definition (with extra options) to LaTeX " + + i = find_token(document.header, '\\use_non_tex_fonts', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\use_non_tex_fonts.") + return + if str2bool(get_value(document.header, "\\use_non_tex_fonts", i)): + return + + osf = False + y = find_token(document.header, "\\font_osf true", 0) + if y != -1: + osf = True + + regexp = re.compile(r'(\\font_roman_opts)') + x = find_re(document.header, regexp, 0) + if x == -1 and not osf: + return + + opts = "" + if x != -1: + # We need to use this regex since split() does not handle quote protection + romanopts = re.findall(r'[^"\s]\S*|".+?"', document.header[x]) + opts = romanopts[1].strip('"') + if osf: + if opts != "": + opts += ", " + opts += "osf" + + i = find_token(document.header, "\\font_roman", 0) + if i == -1: + return + + # We need to use this regex since split() does not handle quote protection + romanfont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + roman = romanfont[1].strip('"') + if roman != "NotoSerif-TLF": + return + + j = find_token(document.header, "\\font_sans", 0) + if j == -1: + return + + # We need to use this regex since split() does not handle quote protection + sffont = re.findall(r'[^"\s]\S*|".+?"', document.header[j]) + sf = sffont[1].strip('"') + if sf != "default": + return + + j = find_token(document.header, "\\font_typewriter", 0) + if j == -1: + return + + # We need to use this regex since split() does not handle quote protection + ttfont = re.findall(r'[^"\s]\S*|".+?"', document.header[j]) + tt = ttfont[1].strip('"') + if tt != "default": + return + + # So we have noto as "complete font" + romanfont[1] = '"default"' + document.header[i] = " ".join(romanfont) + + preamble = "\\usepackage[" + preamble += opts + preamble += "]{noto}" + add_to_preamble(document, [preamble]) + if osf: + document.header[y] = "\\font_osf false" + if x != -1: + del document.header[x] + + +def revert_notoFonts_xopts(document): + " Revert native (extended) Noto font definition (with extra options) to LaTeX " + + i = find_token(document.header, '\\use_non_tex_fonts', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\use_non_tex_fonts.") + return + if str2bool(get_value(document.header, "\\use_non_tex_fonts", i)): + return + + fontmap = dict() + fm = createFontMapping(['Noto']) + if revert_fonts(document, fm, fontmap, True): + add_preamble_fonts(document, fontmap) + + +def revert_IBMFonts_xopts(document): + " Revert native IBM font definition (with extra options) to LaTeX " + + i = find_token(document.header, '\\use_non_tex_fonts', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\use_non_tex_fonts.") + return + if str2bool(get_value(document.header, "\\use_non_tex_fonts", i)): + return + + fontmap = dict() + fm = createFontMapping(['IBM']) + ft = "" + if revert_fonts(document, fm, fontmap, True): + add_preamble_fonts(document, fontmap) + + +def revert_AdobeFonts_xopts(document): + " Revert native Adobe font definition (with extra options) to LaTeX " + + i = find_token(document.header, '\\use_non_tex_fonts', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\use_non_tex_fonts.") + return + if str2bool(get_value(document.header, "\\use_non_tex_fonts", i)): + return + + fontmap = dict() + fm = createFontMapping(['Adobe']) + ft = "" + if revert_fonts(document, fm, fontmap, True): + add_preamble_fonts(document, fontmap) + + +def convert_osf(document): + " Convert \\font_osf param to new format " + + NonTeXFonts = False + i = find_token(document.header, '\\use_non_tex_fonts', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\use_non_tex_fonts.") + else: + NonTeXFonts = str2bool(get_value(document.header, "\\use_non_tex_fonts", i)) + + i = find_token(document.header, '\\font_osf', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_osf.") + return + + osfsf = ["biolinum", "ADOBESourceSansPro", "NotoSansRegular", "NotoSansMedium", "NotoSansThin", "NotoSansLight", "NotoSansExtralight" ] + osftt = ["ADOBESourceCodePro", "NotoMonoRegular" ] + + osfval = str2bool(get_value(document.header, "\\font_osf", i)) + document.header[i] = document.header[i].replace("\\font_osf", "\\font_roman_osf") + + if NonTeXFonts: + document.header.insert(i, "\\font_sans_osf false") + document.header.insert(i + 1, "\\font_typewriter_osf false") + return + + if osfval: + x = find_token(document.header, "\\font_sans", 0) + if x == -1: + document.warning("Malformed LyX document: Missing \\font_sans.") + else: + # We need to use this regex since split() does not handle quote protection + sffont = re.findall(r'[^"\s]\S*|".+?"', document.header[x]) + sf = sffont[1].strip('"') + if sf in osfsf: + document.header.insert(i, "\\font_sans_osf true") + else: + document.header.insert(i, "\\font_sans_osf false") + + x = find_token(document.header, "\\font_typewriter", 0) + if x == -1: + document.warning("Malformed LyX document: Missing \\font_typewriter.") + else: + # We need to use this regex since split() does not handle quote protection + ttfont = re.findall(r'[^"\s]\S*|".+?"', document.header[x]) + tt = ttfont[1].strip('"') + if tt in osftt: + document.header.insert(i + 1, "\\font_typewriter_osf true") + else: + document.header.insert(i + 1, "\\font_typewriter_osf false") + + else: + document.header.insert(i, "\\font_sans_osf false") + document.header.insert(i + 1, "\\font_typewriter_osf false") + + +def revert_osf(document): + " Revert \\font_*_osf params " + + NonTeXFonts = False + i = find_token(document.header, '\\use_non_tex_fonts', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\use_non_tex_fonts.") + else: + NonTeXFonts = str2bool(get_value(document.header, "\\use_non_tex_fonts", i)) + + i = find_token(document.header, '\\font_roman_osf', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_roman_osf.") + return + + osfval = str2bool(get_value(document.header, "\\font_roman_osf", i)) + document.header[i] = document.header[i].replace("\\font_roman_osf", "\\font_osf") + + i = find_token(document.header, '\\font_sans_osf', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_sans_osf.") + return + + osfval = str2bool(get_value(document.header, "\\font_sans_osf", i)) + del document.header[i] + + i = find_token(document.header, '\\font_typewriter_osf', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_typewriter_osf.") + return + + osfval |= str2bool(get_value(document.header, "\\font_typewriter_osf", i)) + del document.header[i] + + if osfval: + i = find_token(document.header, '\\font_osf', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_osf.") + return + document.header[i] = "\\font_osf true" + + +def revert_texfontopts(document): + " Revert native TeX font definitions (with extra options) to LaTeX " + + i = find_token(document.header, '\\use_non_tex_fonts', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\use_non_tex_fonts.") + return + if str2bool(get_value(document.header, "\\use_non_tex_fonts", i)): + return + + rmfonts = ["ccfonts", "cochineal", "utopia", "garamondx", "libertine", "lmodern", "palatino", "times", "xcharter" ] + + # First the sf (biolinum only) + regexp = re.compile(r'(\\font_sans_opts)') + x = find_re(document.header, regexp, 0) + if x != -1: + # We need to use this regex since split() does not handle quote protection + sfopts = re.findall(r'[^"\s]\S*|".+?"', document.header[x]) + opts = sfopts[1].strip('"') + i = find_token(document.header, "\\font_sans", 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_sans.") + else: + # We need to use this regex since split() does not handle quote protection + sffont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + sans = sffont[1].strip('"') + if sans == "biolinum": + sf_scale = 100.0 + sffont[1] = '"default"' + document.header[i] = " ".join(sffont) + osf = False + j = find_token(document.header, "\\font_sans_osf true", 0) + if j != -1: + osf = True + k = find_token(document.header, "\\font_sf_scale", 0) + if k == -1: + document.warning("Malformed LyX document: Missing \\font_sf_scale.") + else: + sfscale = document.header[k].split() + val = sfscale[1] + sfscale[1] = "100" + document.header[k] = " ".join(sfscale) + try: + # float() can throw + sf_scale = float(val) + except: + document.warning("Invalid font_sf_scale value: " + val) + preamble = "\\usepackage[" + if osf: + document.header[j] = "\\font_sans_osf false" + preamble += "osf," + if sf_scale != 100.0: + preamble += 'scaled=' + str(sf_scale / 100.0) + ',' + preamble += opts + preamble += "]{biolinum}" + add_to_preamble(document, [preamble]) + del document.header[x] + + regexp = re.compile(r'(\\font_roman_opts)') + x = find_re(document.header, regexp, 0) + if x == -1: + return + + # We need to use this regex since split() does not handle quote protection + romanopts = re.findall(r'[^"\s]\S*|".+?"', document.header[x]) + opts = romanopts[1].strip('"') + + i = find_token(document.header, "\\font_roman", 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_roman.") + return + else: + # We need to use this regex since split() does not handle quote protection + romanfont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + roman = romanfont[1].strip('"') + if not roman in rmfonts: + return + romanfont[1] = '"default"' + document.header[i] = " ".join(romanfont) + package = roman + if roman == "utopia": + package = "fourier" + elif roman == "palatino": + package = "mathpazo" + elif roman == "times": + package = "mathptmx" + elif roman == "xcharter": + package = "XCharter" + osf = "" + j = find_token(document.header, "\\font_roman_osf true", 0) + if j != -1: + if roman == "cochineal": + osf = "proportional,osf," + elif roman == "utopia": + osf = "oldstyle," + elif roman == "garamondx": + osf = "osfI," + elif roman == "libertine": + osf = "osf," + elif roman == "palatino": + osf = "osf," + elif roman == "xcharter": + osf = "osf," + document.header[j] = "\\font_roman_osf false" + k = find_token(document.header, "\\font_sc true", 0) + if k != -1: + if roman == "utopia": + osf += "expert," + if roman == "palatino" and osf == "": + osf = "sc," + document.header[k] = "\\font_sc false" + preamble = "\\usepackage[" + preamble += osf + preamble += opts + preamble += "]{" + package + "}" + add_to_preamble(document, [preamble]) + del document.header[x] + + +def convert_CantarellFont(document): + " Handle Cantarell font definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fm = createFontMapping(['Cantarell']) + convert_fonts(document, fm, "oldstyle") + +def revert_CantarellFont(document): + " Revert native Cantarell font definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fontmap = dict() + fm = createFontMapping(['Cantarell']) + if revert_fonts(document, fm, fontmap, False, True): + add_preamble_fonts(document, fontmap) + +def convert_ChivoFont(document): + " Handle Chivo font definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fm = createFontMapping(['Chivo']) + convert_fonts(document, fm, "oldstyle") + +def revert_ChivoFont(document): + " Revert native Chivo font definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fontmap = dict() + fm = createFontMapping(['Chivo']) + if revert_fonts(document, fm, fontmap, False, True): + add_preamble_fonts(document, fontmap) + + +def convert_FiraFont(document): + " Handle Fira font definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fm = createFontMapping(['Fira']) + convert_fonts(document, fm, "lf") + +def revert_FiraFont(document): + " Revert native Fira font definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fontmap = dict() + fm = createFontMapping(['Fira']) + if revert_fonts(document, fm, fontmap, False, True): + add_preamble_fonts(document, fontmap) + + +def convert_Semibolds(document): + " Move semibold options to extraopts " + + NonTeXFonts = False + i = find_token(document.header, '\\use_non_tex_fonts', 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\use_non_tex_fonts.") + else: + NonTeXFonts = str2bool(get_value(document.header, "\\use_non_tex_fonts", i)) + + i = find_token(document.header, "\\font_roman", 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_roman.") + else: + # We need to use this regex since split() does not handle quote protection + romanfont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + roman = romanfont[1].strip('"') + if roman == "IBMPlexSerifSemibold": + romanfont[1] = '"IBMPlexSerif"' + document.header[i] = " ".join(romanfont) + + if NonTeXFonts == False: + regexp = re.compile(r'(\\font_roman_opts)') + x = find_re(document.header, regexp, 0) + if x == -1: + # Sensible place to insert tag + fo = find_token(document.header, "\\font_sf_scale") + if fo == -1: + document.warning("Malformed LyX document! Missing \\font_sf_scale") + else: + document.header.insert(fo, "\\font_roman_opts \"semibold\"") + else: + # We need to use this regex since split() does not handle quote protection + romanopts = re.findall(r'[^"\s]\S*|".+?"', document.header[x]) + document.header[x] = "\\font_roman_opts \"semibold, " + romanopts[1].strip('"') + "\"" + + i = find_token(document.header, "\\font_sans", 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_sans.") + else: + # We need to use this regex since split() does not handle quote protection + sffont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + sf = sffont[1].strip('"') + if sf == "IBMPlexSansSemibold": + sffont[1] = '"IBMPlexSans"' + document.header[i] = " ".join(sffont) + + if NonTeXFonts == False: + regexp = re.compile(r'(\\font_sans_opts)') + x = find_re(document.header, regexp, 0) + if x == -1: + # Sensible place to insert tag + fo = find_token(document.header, "\\font_sf_scale") + if fo == -1: + document.warning("Malformed LyX document! Missing \\font_sf_scale") + else: + document.header.insert(fo, "\\font_sans_opts \"semibold\"") + else: + # We need to use this regex since split() does not handle quote protection + sfopts = re.findall(r'[^"\s]\S*|".+?"', document.header[x]) + document.header[x] = "\\font_sans_opts \"semibold, " + sfopts[1].strip('"') + "\"" + + i = find_token(document.header, "\\font_typewriter", 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_typewriter.") + else: + # We need to use this regex since split() does not handle quote protection + ttfont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + tt = ttfont[1].strip('"') + if tt == "IBMPlexMonoSemibold": + ttfont[1] = '"IBMPlexMono"' + document.header[i] = " ".join(ttfont) + + if NonTeXFonts == False: + regexp = re.compile(r'(\\font_typewriter_opts)') + x = find_re(document.header, regexp, 0) + if x == -1: + # Sensible place to insert tag + fo = find_token(document.header, "\\font_tt_scale") + if fo == -1: + document.warning("Malformed LyX document! Missing \\font_tt_scale") + else: + document.header.insert(fo, "\\font_typewriter_opts \"semibold\"") + else: + # We need to use this regex since split() does not handle quote protection + ttopts = re.findall(r'[^"\s]\S*|".+?"', document.header[x]) + document.header[x] = "\\font_typewriter_opts \"semibold, " + sfopts[1].strip('"') + "\"" + + +def convert_NotoRegulars(document): + " Merge diverse noto reagular fonts " + + i = find_token(document.header, "\\font_roman", 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_roman.") + else: + # We need to use this regex since split() does not handle quote protection + romanfont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + roman = romanfont[1].strip('"') + if roman == "NotoSerif-TLF": + romanfont[1] = '"NotoSerifRegular"' + document.header[i] = " ".join(romanfont) + + i = find_token(document.header, "\\font_sans", 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_sans.") + else: + # We need to use this regex since split() does not handle quote protection + sffont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + sf = sffont[1].strip('"') + if sf == "NotoSans-TLF": + sffont[1] = '"NotoSansRegular"' + document.header[i] = " ".join(sffont) + + i = find_token(document.header, "\\font_typewriter", 0) + if i == -1: + document.warning("Malformed LyX document: Missing \\font_typewriter.") + else: + # We need to use this regex since split() does not handle quote protection + ttfont = re.findall(r'[^"\s]\S*|".+?"', document.header[i]) + tt = ttfont[1].strip('"') + if tt == "NotoMono-TLF": + ttfont[1] = '"NotoMonoRegular"' + document.header[i] = " ".join(ttfont) + + +def convert_CrimsonProFont(document): + " Handle CrimsonPro font definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fm = createFontMapping(['CrimsonPro']) + convert_fonts(document, fm, "lf") + +def revert_CrimsonProFont(document): + " Revert native CrimsonPro font definition to LaTeX " + + if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1: + fontmap = dict() + fm = createFontMapping(['CrimsonPro']) + if revert_fonts(document, fm, fontmap, False, True): + add_preamble_fonts(document, fontmap) + + +def revert_pagesizes(document): + " Revert new page sizes in memoir and KOMA to options " + + if document.textclass != "memoir" and document.textclass[:2] != "scr": + return + + i = find_token(document.header, "\\use_geometry true", 0) + if i != -1: + return + + defsizes = ["default", "custom", "letterpaper", "legalpaper", "executivepaper", "a4paper", "a5paper", "b5paper"] + + i = find_token(document.header, "\\papersize", 0) + if i == -1: + document.warning("Malformed LyX document! Missing \\papersize header.") + return + val = get_value(document.header, "\\papersize", i) + if val in defsizes: + # nothing to do + return + + document.header[i] = "\\papersize default" + + i = find_token(document.header, "\\options", 0) + if i == -1: + i = find_token(document.header, "\\textclass", 0) + if i == -1: + document.warning("Malformed LyX document! Missing \\textclass header.") + return + document.header.insert(i, "\\options " + val) + return + document.header[i] = document.header[i] + "," + val + + +def convert_pagesizes(document): + " Convert to new page sizes in memoir and KOMA to options " + + if document.textclass != "memoir" and document.textclass[:3] != "scr": + return + + i = find_token(document.header, "\\use_geometry true", 0) + if i != -1: + return + + defsizes = ["default", "custom", "letterpaper", "legalpaper", "executivepaper", "a4paper", "a5paper", "b5paper"] + + i = find_token(document.header, "\\papersize", 0) + if i == -1: + document.warning("Malformed LyX document! Missing \\papersize header.") + return + val = get_value(document.header, "\\papersize", i) + if val in defsizes: + # nothing to do + return + + i = find_token(document.header, "\\use_geometry false", 0) + if i != -1: + # Maintain use of geometry + document.header[1] = "\\use_geometry true" + +def revert_komafontsizes(document): + " Revert new font sizes in KOMA to options " + + if document.textclass[:3] != "scr": + return + + i = find_token(document.header, "\\paperfontsize", 0) + if i == -1: + document.warning("Malformed LyX document! Missing \\paperfontsize header.") + return + + defsizes = ["default", "10", "11", "12"] + + val = get_value(document.header, "\\paperfontsize", i) + if val in defsizes: + # nothing to do + return + + document.header[i] = "\\paperfontsize default" + + fsize = "fontsize=" + val + + i = find_token(document.header, "\\options", 0) + if i == -1: + i = find_token(document.header, "\\textclass", 0) + if i == -1: + document.warning("Malformed LyX document! Missing \\textclass header.") + return + document.header.insert(i, "\\options " + fsize) + return + document.header[i] = document.header[i] + "," + fsize + + +def revert_dupqualicites(document): + " Revert qualified citation list commands with duplicate keys to ERT " + + # LyX 2.3 only supports qualified citation lists with unique keys. Thus, + # we need to revert those with multiple uses of the same key. + + # Get cite engine + engine = "basic" + i = find_token(document.header, "\\cite_engine", 0) + if i == -1: + document.warning("Malformed document! Missing \\cite_engine") + else: + engine = get_value(document.header, "\\cite_engine", i) + + if not engine in ["biblatex", "biblatex-natbib"]: + return + + # Citation insets that support qualified lists, with their LaTeX code + ql_citations = { + "cite" : "cites", + "Cite" : "Cites", + "citet" : "textcites", + "Citet" : "Textcites", + "citep" : "parencites", + "Citep" : "Parencites", + "Footcite" : "Smartcites", + "footcite" : "smartcites", + "Autocite" : "Autocites", + "autocite" : "autocites", + } + + i = 0 + while (True): + i = find_token(document.body, "\\begin_inset CommandInset citation", i) + if i == -1: + break + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Can't find end of citation inset at line %d!!" %(i)) + i += 1 + continue + + k = find_token(document.body, "LatexCommand", i, j) + if k == -1: + document.warning("Can't find LatexCommand for citation inset at line %d!" %(i)) + i = j + 1 + continue + + cmd = get_value(document.body, "LatexCommand", k) + if not cmd in list(ql_citations.keys()): + i = j + 1 + continue + + pres = find_token(document.body, "pretextlist", i, j) + posts = find_token(document.body, "posttextlist", i, j) + if pres == -1 and posts == -1: + # nothing to do. + i = j + 1 + continue + + key = get_quoted_value(document.body, "key", i, j) + if not key: + document.warning("Citation inset at line %d does not have a key!" %(i)) + i = j + 1 + continue + + keys = key.split(",") + ukeys = list(set(keys)) + if len(keys) == len(ukeys): + # no duplicates. + i = j + 1 + continue + + pretexts = get_quoted_value(document.body, "pretextlist", pres) + posttexts = get_quoted_value(document.body, "posttextlist", posts) + + pre = get_quoted_value(document.body, "before", i, j) + post = get_quoted_value(document.body, "after", i, j) + prelist = pretexts.split("\t") + premap = dict() + for pp in prelist: + ppp = pp.split(" ", 1) + val = "" + if len(ppp) > 1: + val = ppp[1] + else: + val = "" + if ppp[0] in premap: + premap[ppp[0]] = premap[ppp[0]] + "\t" + val + else: + premap[ppp[0]] = val + postlist = posttexts.split("\t") + postmap = dict() + num = 1 + for pp in postlist: + ppp = pp.split(" ", 1) + val = "" + if len(ppp) > 1: + val = ppp[1] + else: + val = "" + if ppp[0] in postmap: + postmap[ppp[0]] = postmap[ppp[0]] + "\t" + val + else: + postmap[ppp[0]] = val + # Replace known new commands with ERT + if "(" in pre or ")" in pre: + pre = "{" + pre + "}" + if "(" in post or ")" in post: + post = "{" + post + "}" + res = "\\" + ql_citations[cmd] + if pre: + res += "(" + pre + ")" + if post: + res += "(" + post + ")" + elif pre: + res += "()" + for kk in keys: + if premap.get(kk, "") != "": + akeys = premap[kk].split("\t", 1) + akey = akeys[0] + if akey != "": + res += "[" + akey + "]" + if len(akeys) > 1: + premap[kk] = "\t".join(akeys[1:]) + else: + premap[kk] = "" + if postmap.get(kk, "") != "": + akeys = postmap[kk].split("\t", 1) + akey = akeys[0] + if akey != "": + res += "[" + akey + "]" + if len(akeys) > 1: + postmap[kk] = "\t".join(akeys[1:]) + else: + postmap[kk] = "" + elif premap.get(kk, "") != "": + res += "[]" + res += "{" + kk + "}" + document.body[i:j+1] = put_cmd_in_ert([res]) + + +def convert_pagesizenames(document): + " Convert LyX page sizes names " + + i = find_token(document.header, "\\papersize", 0) + if i == -1: + document.warning("Malformed LyX document! Missing \\papersize header.") + return + oldnames = ["letterpaper", "legalpaper", "executivepaper", \ + "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", "a6paper", \ + "b0paper", "b1paper", "b2paper", "b3paper", "b4paper", "b5paper", "b6paper", \ + "c0paper", "c1paper", "c2paper", "c3paper", "c4paper", "c5paper", "c6paper"] + val = get_value(document.header, "\\papersize", i) + if val in oldnames: + newval = val.replace("paper", "") + document.header[i] = "\\papersize " + newval + +def revert_pagesizenames(document): + " Convert LyX page sizes names " + + i = find_token(document.header, "\\papersize", 0) + if i == -1: + document.warning("Malformed LyX document! Missing \\papersize header.") + return + newnames = ["letter", "legal", "executive", \ + "a0", "a1", "a2", "a3", "a4", "a5", "a6", \ + "b0", "b1", "b2", "b3", "b4", "b5", "b6", \ + "c0", "c1", "c2", "c3", "c4", "c5", "c6"] + val = get_value(document.header, "\\papersize", i) + if val in newnames: + newval = val + "paper" + document.header[i] = "\\papersize " + newval + + +def revert_theendnotes(document): + " Reverts native support of \\theendnotes to TeX-code " + + if not "endnotes" in document.get_module_list() and not "foottoend" in document.get_module_list(): + return + + i = 0 + while True: + i = find_token(document.body, "\\begin_inset FloatList endnote", i + 1) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of FloatList inset") + continue + + document.body[i : j + 1] = put_cmd_in_ert("\\theendnotes") + + +def revert_enotez(document): + " Reverts native support of enotez package to TeX-code " + + if not "enotez" in document.get_module_list() and not "foottoenotez" in document.get_module_list(): + return + + use = False + if find_token(document.body, "\\begin_inset Flex Endnote", 0) != -1: + use = True + + revert_flex_inset(document.body, "Endnote", "\\endnote") + + i = 0 + while True: + i = find_token(document.body, "\\begin_inset FloatList endnote", i + 1) + if i == -1: + break + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of FloatList inset") + continue + + use = True + document.body[i : j + 1] = put_cmd_in_ert("\\printendnotes") + + if use: + add_to_preamble(document, ["\\usepackage{enotez}"]) + document.del_module("enotez") + document.del_module("foottoenotez") + + +def revert_memoir_endnotes(document): + " Reverts native support of memoir endnotes to TeX-code " + + if document.textclass != "memoir": + return + + encommand = "\\pagenote" + modules = document.get_module_list() + if "enotez" in modules or "foottoenotez" in modules or "endnotes" in modules or "foottoend" in modules: + encommand = "\\endnote" + + revert_flex_inset(document.body, "Endnote", encommand) + + i = 0 + while True: + i = find_token(document.body, "\\begin_inset FloatList pagenote", i + 1) + if i == -1: + break + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Can't find end of FloatList inset") + continue + + if document.body[i] == "\\begin_inset FloatList pagenote*": + document.body[i : j + 1] = put_cmd_in_ert("\\printpagenotes*") + else: + document.body[i : j + 1] = put_cmd_in_ert("\\printpagenotes") + add_to_preamble(document, ["\\makepagenote"]) + + +def revert_totalheight(document): + " Reverts graphics height parameter from totalheight to height " + + i = 0 + while (True): + i = find_token(document.body, "\\begin_inset Graphics", i) + if i == -1: + break + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Can't find end of graphics inset at line %d!!" %(i)) + i += 1 + continue + + rx = re.compile(r'\s*special\s*(\S+)$') + k = find_re(document.body, rx, i, j) + special = "" + oldheight = "" + if k != -1: + m = rx.match(document.body[k]) + if m: + special = m.group(1) + mspecial = special.split(',') + for spc in mspecial: + if spc[:7] == "height=": + oldheight = spc.split('=')[1] + mspecial.remove(spc) + break + if len(mspecial) > 0: + special = ",".join(mspecial) + else: + special = "" + + rx = re.compile(r'(\s*height\s*)(\S+)$') + kk = find_re(document.body, rx, i, j) + if kk != -1: + m = rx.match(document.body[kk]) + val = "" + if m: + val = m.group(2) + if k != -1: + if special != "": + val = val + "," + special + document.body[k] = "\tspecial " + "totalheight=" + val + else: + document.body.insert(kk, "\tspecial totalheight=" + val) + if oldheight != "": + document.body[kk] = m.group(1) + oldheight + else: + del document.body[kk] + elif oldheight != "": + document.body.insert(k, "\theight " + oldheight) + i = j + 1 + + +def convert_totalheight(document): + " Converts graphics height parameter from totalheight to height " + + i = 0 + while (True): + i = find_token(document.body, "\\begin_inset Graphics", i) + if i == -1: + break + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Can't find end of graphics inset at line %d!!" %(i)) + i += 1 + continue + + rx = re.compile(r'\s*special\s*(\S+)$') + k = find_re(document.body, rx, i, j) + special = "" + newheight = "" + if k != -1: + m = rx.match(document.body[k]) + if m: + special = m.group(1) + mspecial = special.split(',') + for spc in mspecial: + if spc[:12] == "totalheight=": + newheight = spc.split('=')[1] + mspecial.remove(spc) + break + if len(mspecial) > 0: + special = ",".join(mspecial) + else: + special = "" + + rx = re.compile(r'(\s*height\s*)(\S+)$') + kk = find_re(document.body, rx, i, j) + if kk != -1: + m = rx.match(document.body[kk]) + val = "" + if m: + val = m.group(2) + if k != -1: + if special != "": + val = val + "," + special + document.body[k] = "\tspecial " + "height=" + val + else: + document.body.insert(kk + 1, "\tspecial height=" + val) + if newheight != "": + document.body[kk] = m.group(1) + newheight + else: + del document.body[kk] + elif newheight != "": + document.body.insert(k, "\theight " + newheight) + i = j + 1 ## # Conversion hub @@ -687,11 +3600,72 @@ convert = [ [555, []], [556, []], [557, [convert_vcsinfo]], - [558, [removeFrontMatterStyles]] + [558, [removeFrontMatterStyles]], + [559, []], + [560, []], + [561, [convert_latexFonts]], # Handle dejavu, ibmplex fonts in GUI + [562, []], + [563, []], + [564, []], + [565, [convert_AdobeFonts]], # Handle adobe fonts in GUI + [566, [convert_hebrew_parentheses]], + [567, []], + [568, []], + [569, []], + [570, []], + [571, []], + [572, [convert_notoFonts]], # Added options thin, light, extralight for Noto + [573, [convert_inputencoding_namechange]], + [574, [convert_ruby_module, convert_utf8_japanese]], + [575, [convert_lineno]], + [576, []], + [577, [convert_linggloss]], + [578, []], + [579, []], + [580, []], + [581, [convert_osf]], + [582, [convert_AdobeFonts,convert_latexFonts,convert_notoFonts,convert_CantarellFont,convert_FiraFont]],# old font re-converterted due to extra options + [583, [convert_ChivoFont,convert_Semibolds,convert_NotoRegulars,convert_CrimsonProFont]], + [584, []], + [585, [convert_pagesizes]], + [586, []], + [587, [convert_pagesizenames]], + [588, []], + [589, [convert_totalheight]] ] -revert = [ - [557, [addFrontMatterStyles]], +revert = [[588, [revert_totalheight]], + [587, [revert_memoir_endnotes,revert_enotez,revert_theendnotes]], + [586, [revert_pagesizenames]], + [585, [revert_dupqualicites]], + [584, [revert_pagesizes,revert_komafontsizes]], + [583, [revert_vcsinfo_rev_abbrev]], + [582, [revert_ChivoFont,revert_CrimsonProFont]], + [581, [revert_CantarellFont,revert_FiraFont]], + [580, [revert_texfontopts,revert_osf]], + [579, [revert_minionpro, revert_plainNotoFonts_xopts, revert_notoFonts_xopts, revert_IBMFonts_xopts, revert_AdobeFonts_xopts, revert_font_opts]], # keep revert_font_opts last! + [578, [revert_babelfont]], + [577, [revert_drs]], + [576, [revert_linggloss, revert_subexarg]], + [575, [revert_new_languages]], + [574, [revert_lineno]], + [573, [revert_ruby_module, revert_utf8_japanese]], + [572, [revert_inputencoding_namechange]], + [571, [revert_notoFonts]], + [570, [revert_cmidruletrimming]], + [569, [revert_bibfileencodings]], + [568, [revert_tablestyle]], + [567, [revert_soul]], + [566, [revert_malayalam]], + [565, [revert_hebrew_parentheses]], + [564, [revert_AdobeFonts]], + [563, [revert_lformatinfo]], + [562, [revert_listpargs]], + [561, [revert_l7ninfo]], + [560, [revert_latexFonts]], # Handle dejavu, ibmplex fonts in user preamble + [559, [revert_timeinfo, revert_namenoextinfo]], + [558, [revert_dateinfo]], + [557, [addFrontMatterStyles]], [556, [revert_vcsinfo]], [555, [revert_bibencoding]], [554, [revert_vcolumns]],