1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # Copyright (C) 2018 The LyX team
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 """ Convert files to the file format generated by lyx 2.4"""
25 from datetime import (datetime, date, time)
27 # Uncomment only what you need to import, please.
29 from parser_tools import (count_pars_in_inset, del_token, find_end_of_inset,
30 find_end_of_layout, find_token, find_token_backwards, find_re, get_bool_value,
31 get_containing_layout, get_option_value, get_value, get_quoted_value)
32 # del_value, del_complete_lines,
33 # find_complete_lines, find_end_of,
34 # find_re, find_substring,
35 # get_containing_inset,
36 # is_in_inset, set_bool_value
37 # find_tokens, find_token_exact, check_token
39 from lyx2lyx_tools import (put_cmd_in_ert, add_to_preamble, revert_language, revert_flex_inset)
40 # revert_font_attrs, insert_to_preamble, latex_length
41 # get_ert, lyx2latex, lyx2verbatim, length_in_bp, convert_info_insets
42 # revert_flex_inset, hex2ratio, str2bool
44 ####################################################################
45 # Private helper functions
47 def add_preamble_fonts(document, fontmap):
48 " Add collected font-packages with their option to user-preamble"
51 if len(fontmap[pkg]) > 0:
52 xoption = "[" + ",".join(fontmap[pkg]) + "]"
55 preamble = "\\usepackage" + xoption + "{%s}" % pkg
56 add_to_preamble(document, [preamble])
59 def createkey(pkg, options):
61 return pkg + ':' + "-".join(options)
65 self.fontname = None # key into font2pkgmap
66 self.fonttype = None # roman,sans,typewriter,math
67 self.scaletype = None # None,sf,tt
68 self.scaleopt = None # None, 'scaled', 'scale'
72 self.pkgkey = None # key into pkg2fontmap
75 self.pkgkey = createkey(self.package, self.options)
79 self.font2pkgmap = dict()
80 self.pkg2fontmap = dict()
81 self.pkginmap = dict() # defines, if a map for package exists
83 def expandFontMapping(self, font_list, font_type, scale_type, pkg, scaleopt = None):
84 " Expand fontinfo mapping"
86 # fontlist: list of fontnames, each element
87 # may contain a ','-separated list of needed options
88 # like e.g. 'IBMPlexSansCondensed,condensed'
89 # font_type: one of 'roman', 'sans', 'typewriter', 'math'
90 # scale_type: one of None, 'sf', 'tt'
91 # pkg: package defining the font. Defaults to fontname if None
92 # scaleopt: one of None, 'scale', 'scaled', or some other string
93 # to be used in scale option (e.g. scaled=0.7)
96 fe.fonttype = font_type
97 fe.scaletype = scale_type
100 fe.fontname = font_name
102 fe.scaleopt = scaleopt
104 fe.package = font_name
108 self.font2pkgmap[font_name] = fe
109 if fe.pkgkey in self.pkg2fontmap:
110 # Repeated the same entry? Check content
111 if self.pkg2fontmap[fe.pkgkey] != font_name:
112 document.error("Something is wrong in pkgname+options <-> fontname mapping")
113 self.pkg2fontmap[fe.pkgkey] = font_name
114 self.pkginmap[fe.package] = 1
116 def getfontname(self, pkg, options):
118 pkgkey = createkey(pkg, options)
119 if not pkgkey in self.pkg2fontmap:
121 fontname = self.pkg2fontmap[pkgkey]
122 if not fontname in self.font2pkgmap:
123 document.error("Something is wrong in pkgname+options <-> fontname mapping")
125 if pkgkey == self.font2pkgmap[fontname].pkgkey:
129 def createFontMapping(fontlist):
130 # Create info for known fonts for the use in
131 # convert_latexFonts() and
132 # revert_latexFonts()
134 # * Would be more handy to parse latexFonts file,
135 # but the path to this file is unknown
136 # * For now, add DejaVu and IBMPlex only.
137 # * Expand, if desired
139 for font in fontlist:
141 fm.expandFontMapping(['DejaVuSerif', 'DejaVuSerifCondensed'], "roman", None, None)
142 fm.expandFontMapping(['DejaVuSans','DejaVuSansCondensed'], "sans", "sf", None, "scaled")
143 fm.expandFontMapping(['DejaVuSansMono'], "typewriter", "tt", None, "scaled")
145 fm.expandFontMapping(['IBMPlexSerif', 'IBMPlexSerifThin,thin',
146 'IBMPlexSerifExtraLight,extralight', 'IBMPlexSerifLight,light',
147 'IBMPlexSerifSemibold,semibold'],
148 "roman", None, "plex-serif")
149 fm.expandFontMapping(['IBMPlexSans','IBMPlexSansCondensed,condensed',
150 'IBMPlexSansThin,thin', 'IBMPlexSansExtraLight,extralight',
151 'IBMPlexSansLight,light', 'IBMPlexSansSemibold,semibold'],
152 "sans", "sf", "plex-sans", "scale")
153 fm.expandFontMapping(['IBMPlexMono', 'IBMPlexMonoThin,thin',
154 'IBMPlexMonoExtraLight,extralight', 'IBMPlexMonoLight,light',
155 'IBMPlexMonoSemibold,semibold'],
156 "typewriter", "tt", "plex-mono", "scale")
157 elif font == 'Adobe':
158 fm.expandFontMapping(['ADOBESourceSerifPro'], "roman", None, "sourceserifpro")
159 fm.expandFontMapping(['ADOBESourceSansPro'], "sans", "sf", "sourcesanspro", "scaled")
160 fm.expandFontMapping(['ADOBESourceCodePro'], "typewriter", "tt", "sourcecodepro", "scaled")
162 fm.expandFontMapping(['NotoSerifRegular,regular', 'NotoSerifMedium,medium',
163 'NotoSerifThin,thin', 'NotoSerifLight,light',
164 'NotoSerifExtralight,extralight'],
165 "roman", None, "noto-serif")
166 fm.expandFontMapping(['NotoSansRegular,regular', 'NotoSansMedium,medium',
167 'NotoSansThin,thin', 'NotoSansLight,light',
168 'NotoSansExtralight,extralight'],
169 "sans", "sf", "noto-sans", "scaled")
170 fm.expandFontMapping(['NotoMonoRegular'], "typewriter", "tt", "noto-mono", "scaled")
173 def convert_fonts(document, fm):
174 " Handle font definition to LaTeX "
176 rpkg = re.compile(r'^\\usepackage(\[([^\]]*)\])?\{([^\}]+)\}')
177 rscaleopt = re.compile(r'^scaled?=(.*)')
180 while i < len(document.preamble):
181 i = find_re(document.preamble, rpkg, i)
184 mo = rpkg.search(document.preamble[i])
185 if mo == None or mo.group(2) == None:
188 options = mo.group(2).replace(' ', '').split(",")
192 while o < len(options):
193 mo = rscaleopt.search(options[o])
201 if not pkg in fm.pkginmap:
205 fn = fm.getfontname(pkg, options)
209 del document.preamble[i]
210 fontinfo = fm.font2pkgmap[fn]
211 if fontinfo.scaletype == None:
214 fontscale = "\\font_" + fontinfo.scaletype + "_scale"
215 fontinfo.scaleval = oscale
217 if i > 0 and document.preamble[i-1] == "% Added by lyx2lyx":
218 del document.preamble[i-1]
219 if fontscale != None:
220 j = find_token(document.header, fontscale, 0)
222 val = get_value(document.header, fontscale, j)
226 scale = "%03d" % int(float(oscale) * 100)
227 document.header[j] = fontscale + " " + scale + " " + vals[1]
228 ft = "\\font_" + fontinfo.fonttype
229 j = find_token(document.header, ft, 0)
231 val = get_value(document.header, ft, j)
232 words = val.split() # ! splits also values like '"DejaVu Sans"'
233 words[0] = '"' + fn + '"'
234 document.header[j] = ft + ' ' + ' '.join(words)
236 def revert_fonts(document, fm, fontmap):
237 " Revert native font definition to LaTeX "
238 # fonlist := list of fonts created from the same package
239 # Empty package means that the font-name is the same as the package-name
240 # fontmap (key = package, val += found options) will be filled
241 # and used later in add_preamble_fonts() to be added to user-preamble
243 rfontscale = re.compile(r'^\s*(\\font_(roman|sans|typewriter|math))\s+')
244 rscales = re.compile(r'^\s*(\d+)\s+(\d+)')
246 while i < len(document.header):
247 i = find_re(document.header, rfontscale, i)
250 mo = rfontscale.search(document.header[i])
254 ft = mo.group(1) # 'roman', 'sans', 'typewriter', 'math'
255 val = get_value(document.header, ft, i)
256 words = val.split(' ') # ! splits also values like '"DejaVu Sans"'
257 font = words[0].strip('"') # TeX font name has no whitespace
258 if not font in fm.font2pkgmap:
261 fontinfo = fm.font2pkgmap[font]
262 val = fontinfo.package
263 if not val in fontmap:
265 words[0] = '"default"'
266 document.header[i] = ft + ' ' + ' '.join(words)
267 if fontinfo.scaleopt != None:
268 xval = get_value(document.header, "\\font_" + fontinfo.scaletype + "_scale", 0)
269 mo = rscales.search(xval)
274 # set correct scale option
275 fontmap[val].extend([fontinfo.scaleopt + "=" + format(float(xval1) / 100, '.2f')])
276 if len(fontinfo.options) > 0:
277 fontmap[val].extend(fontinfo.options)
280 ###############################################################################
282 ### Conversion and reversion routines
284 ###############################################################################
286 def convert_inputencoding_namechange(document):
287 " Rename inputencoding settings. "
288 i = find_token(document.header, "\\inputencoding", 0)
291 s = document.header[i].replace("auto", "auto-legacy")
292 document.header[i] = s.replace("default", "auto-legacy-plain")
294 def revert_inputencoding_namechange(document):
295 " Rename inputencoding settings. "
296 i = find_token(document.header, "\\inputencoding", 0)
299 s = document.header[i].replace("auto-legacy-plain", "default")
300 document.header[i] = s.replace("auto-legacy", "auto")
302 def convert_notoFonts(document):
303 " Handle Noto fonts definition to LaTeX "
305 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
306 fm = createFontMapping(['Noto'])
307 convert_fonts(document, fm)
309 def revert_notoFonts(document):
310 " Revert native Noto font definition to LaTeX "
312 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
314 fm = createFontMapping(['Noto'])
315 revert_fonts(document, fm, fontmap)
316 add_preamble_fonts(document, fontmap)
318 def convert_latexFonts(document):
319 " Handle DejaVu and IBMPlex fonts definition to LaTeX "
321 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
322 fm = createFontMapping(['DejaVu', 'IBM'])
323 convert_fonts(document, fm)
325 def revert_latexFonts(document):
326 " Revert native DejaVu font definition to LaTeX "
328 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
330 fm = createFontMapping(['DejaVu', 'IBM'])
331 revert_fonts(document, fm, fontmap)
332 add_preamble_fonts(document, fontmap)
334 def convert_AdobeFonts(document):
335 " Handle DejaVu and IBMPlex fonts definition to LaTeX "
337 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
338 fm = createFontMapping(['Adobe'])
339 convert_fonts(document, fm)
341 def revert_AdobeFonts(document):
342 " Revert native DejaVu font definition to LaTeX "
344 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
346 fm = createFontMapping(['Adobe'])
347 revert_fonts(document, fm, fontmap)
348 add_preamble_fonts(document, fontmap)
350 def removeFrontMatterStyles(document):
351 " Remove styles Begin/EndFrontmatter"
353 layouts = ['BeginFrontmatter', 'EndFrontmatter']
354 for layout in layouts:
357 i = find_token(document.body, '\\begin_layout ' + layout, i)
360 j = find_end_of_layout(document.body, i)
362 document.warning("Malformed LyX document: Can't find end of layout at line %d" % i)
365 while i > 0 and document.body[i-1].strip() == '':
367 while document.body[j+1].strip() == '':
369 document.body[i:j+1] = ['']
371 def addFrontMatterStyles(document):
372 " Use styles Begin/EndFrontmatter for elsarticle"
374 def insertFrontmatter(prefix, line):
376 while above > 0 and document.body[above-1].strip() == '':
379 while document.body[below].strip() == '':
381 document.body[above:below] = ['', '\\begin_layout ' + prefix + 'Frontmatter',
382 '\\begin_inset Note Note',
384 '\\begin_layout Plain Layout',
387 '\\end_inset', '', '',
390 if document.textclass == "elsarticle":
391 layouts = ['Title', 'Title footnote', 'Author', 'Author footnote',
392 'Corresponding author', 'Address', 'Email', 'Abstract', 'Keywords']
395 for layout in layouts:
398 i = find_token(document.body, '\\begin_layout ' + layout, i)
401 k = find_end_of_layout(document.body, i)
403 document.warning("Malformed LyX document: Can't find end of layout at line %d" % i)
406 if first == -1 or i < first:
408 if last == -1 or last <= k:
413 insertFrontmatter('End', last)
414 insertFrontmatter('Begin', first)
416 def convert_lst_literalparam(document):
417 " Add param literal to include inset "
421 i = find_token(document.body, '\\begin_inset CommandInset include', i)
424 j = find_end_of_inset(document.body, i)
426 document.warning("Malformed LyX document: Can't find end of command inset at line %d" % i)
429 while i < j and document.body[i].strip() != '':
431 document.body.insert(i, "literal \"true\"")
434 def revert_lst_literalparam(document):
435 " Remove param literal from include inset "
439 i = find_token(document.body, '\\begin_inset CommandInset include', i)
442 j = find_end_of_inset(document.body, i)
444 document.warning("Malformed LyX document: Can't find end of include inset at line %d" % i)
447 k = find_token(document.body, 'literal', i, j)
454 def revert_paratype(document):
455 " Revert ParaType font definitions to LaTeX "
457 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
459 i1 = find_token(document.header, "\\font_roman \"PTSerif-TLF\"", 0)
460 i2 = find_token(document.header, "\\font_sans \"default\"", 0)
461 i3 = find_token(document.header, "\\font_typewriter \"default\"", 0)
462 j = find_token(document.header, "\\font_sans \"PTSans-TLF\"", 0)
463 sfval = get_value(document.header, "\\font_sf_scale", 0)
468 sfoption = "scaled=" + format(float(sfval) / 100, '.2f')
469 k = find_token(document.header, "\\font_typewriter \"PTMono-TLF\"", 0)
470 ttval = get_value(document.header, "\\font_tt_scale", 0)
475 ttoption = "scaled=" + format(float(ttval) / 100, '.2f')
476 if i1 != -1 and i2 != -1 and i3!= -1:
477 add_to_preamble(document, ["\\usepackage{paratype}"])
480 add_to_preamble(document, ["\\usepackage{PTSerif}"])
481 document.header[i1] = document.header[i1].replace("PTSerif-TLF", "default")
484 add_to_preamble(document, ["\\usepackage[" + sfoption + "]{PTSans}"])
486 add_to_preamble(document, ["\\usepackage{PTSans}"])
487 document.header[j] = document.header[j].replace("PTSans-TLF", "default")
490 add_to_preamble(document, ["\\usepackage[" + ttoption + "]{PTMono}"])
492 add_to_preamble(document, ["\\usepackage{PTMono}"])
493 document.header[k] = document.header[k].replace("PTMono-TLF", "default")
496 def revert_xcharter(document):
497 " Revert XCharter font definitions to LaTeX "
499 i = find_token(document.header, "\\font_roman \"xcharter\"", 0)
503 # replace unsupported font setting
504 document.header[i] = document.header[i].replace("xcharter", "default")
505 # no need for preamble code with system fonts
506 if get_bool_value(document.header, "\\use_non_tex_fonts"):
509 # transfer old style figures setting to package options
510 j = find_token(document.header, "\\font_osf true")
513 document.header[j] = "\\font_osf false"
517 add_to_preamble(document, ["\\usepackage%s{XCharter}"%options])
520 def revert_lscape(document):
521 " Reverts the landscape environment (Landscape module) to TeX-code "
523 if not "landscape" in document.get_module_list():
528 i = find_token(document.body, "\\begin_inset Flex Landscape", i)
531 j = find_end_of_inset(document.body, i)
533 document.warning("Malformed LyX document: Can't find end of Landscape inset")
537 if document.body[i] == "\\begin_inset Flex Landscape (Floating)":
538 document.body[j - 2 : j + 1] = put_cmd_in_ert("\\end{landscape}}")
539 document.body[i : i + 4] = put_cmd_in_ert("\\afterpage{\\begin{landscape}")
540 add_to_preamble(document, ["\\usepackage{afterpage}"])
542 document.body[j - 2 : j + 1] = put_cmd_in_ert("\\end{landscape}")
543 document.body[i : i + 4] = put_cmd_in_ert("\\begin{landscape}")
545 add_to_preamble(document, ["\\usepackage{pdflscape}"])
549 def convert_fontenc(document):
550 " Convert default fontenc setting "
552 i = find_token(document.header, "\\fontencoding global", 0)
556 document.header[i] = document.header[i].replace("global", "auto")
559 def revert_fontenc(document):
560 " Revert default fontenc setting "
562 i = find_token(document.header, "\\fontencoding auto", 0)
566 document.header[i] = document.header[i].replace("auto", "global")
569 def revert_nospellcheck(document):
570 " Remove nospellcheck font info param "
574 i = find_token(document.body, '\\nospellcheck', i)
580 def revert_floatpclass(document):
581 " Remove float placement params 'document' and 'class' "
584 i = find_token(document.header, "\\float_placement class", 0)
586 del document.header[i]
590 i = find_token(document.body, '\\begin_inset Float', i)
593 j = find_end_of_inset(document.body, i)
594 k = find_token(document.body, 'placement class', i, i + 2)
596 k = find_token(document.body, 'placement document', i, i + 2)
604 def revert_floatalignment(document):
605 " Remove float alignment params "
608 i = find_token(document.header, "\\float_alignment", 0)
611 galignment = get_value(document.header, "\\float_alignment", i)
612 del document.header[i]
616 i = find_token(document.body, '\\begin_inset Float', i)
619 j = find_end_of_inset(document.body, i)
621 document.warning("Malformed LyX document: Can't find end of inset at line " + str(i))
623 k = find_token(document.body, 'alignment', i, i + 4)
627 alignment = get_value(document.body, "alignment", k)
628 if alignment == "document":
629 alignment = galignment
631 l = find_token(document.body, "\\begin_layout Plain Layout", i, j)
633 document.warning("Can't find float layout!")
637 if alignment == "left":
638 alcmd = put_cmd_in_ert("\\raggedright{}")
639 elif alignment == "center":
640 alcmd = put_cmd_in_ert("\\centering{}")
641 elif alignment == "right":
642 alcmd = put_cmd_in_ert("\\raggedleft{}")
644 document.body[l+1:l+1] = alcmd
648 def revert_tuftecite(document):
649 " Revert \cite commands in tufte classes "
651 tufte = ["tufte-book", "tufte-handout"]
652 if document.textclass not in tufte:
657 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
660 j = find_end_of_inset(document.body, i)
662 document.warning("Can't find end of citation inset at line %d!!" %(i))
665 k = find_token(document.body, "LatexCommand", i, j)
667 document.warning("Can't find LatexCommand for citation inset at line %d!" %(i))
670 cmd = get_value(document.body, "LatexCommand", k)
674 pre = get_quoted_value(document.body, "before", i, j)
675 post = get_quoted_value(document.body, "after", i, j)
676 key = get_quoted_value(document.body, "key", i, j)
678 document.warning("Citation inset at line %d does not have a key!" %(i))
680 # Replace command with ERT
683 res += "[" + pre + "]"
685 res += "[" + post + "]"
688 res += "{" + key + "}"
689 document.body[i:j+1] = put_cmd_in_ert([res])
693 def revert_stretchcolumn(document):
694 " We remove the column varwidth flags or everything else will become a mess. "
697 i = find_token(document.body, "\\begin_inset Tabular", i)
700 j = find_end_of_inset(document.body, i + 1)
702 document.warning("Malformed LyX document: Could not find end of tabular.")
704 for k in range(i, j):
705 if re.search('^<column.*varwidth="[^"]+".*>$', document.body[k]):
706 document.warning("Converting 'tabularx'/'xltabular' table to normal table.")
707 document.body[k] = document.body[k].replace(' varwidth="true"', '')
711 def revert_vcolumns(document):
712 " Revert standard columns with line breaks etc. "
718 i = find_token(document.body, "\\begin_inset Tabular", i)
721 j = find_end_of_inset(document.body, i)
723 document.warning("Malformed LyX document: Could not find end of tabular.")
727 # Collect necessary column information
729 nrows = int(document.body[i+1].split('"')[3])
730 ncols = int(document.body[i+1].split('"')[5])
732 for k in range(ncols):
733 m = find_token(document.body, "<column", m)
734 width = get_option_value(document.body[m], 'width')
735 varwidth = get_option_value(document.body[m], 'varwidth')
736 alignment = get_option_value(document.body[m], 'alignment')
737 special = get_option_value(document.body[m], 'special')
738 col_info.append([width, varwidth, alignment, special, m])
743 for row in range(nrows):
744 for col in range(ncols):
745 m = find_token(document.body, "<cell", m)
746 multicolumn = get_option_value(document.body[m], 'multicolumn')
747 multirow = get_option_value(document.body[m], 'multirow')
748 width = get_option_value(document.body[m], 'width')
749 rotate = get_option_value(document.body[m], 'rotate')
750 # Check for: linebreaks, multipars, non-standard environments
752 endcell = find_token(document.body, "</cell>", begcell)
754 if find_token(document.body, "\\begin_inset Newline", begcell, endcell) != -1:
756 elif count_pars_in_inset(document.body, begcell + 2) > 1:
758 elif get_value(document.body, "\\begin_layout", begcell) != "Plain Layout":
760 if vcand and rotate == "" and ((multicolumn == "" and multirow == "") or width == ""):
761 if col_info[col][0] == "" and col_info[col][1] == "" and col_info[col][3] == "":
763 alignment = col_info[col][2]
764 col_line = col_info[col][4]
766 if alignment == "center":
767 vval = ">{\\centering}"
768 elif alignment == "left":
769 vval = ">{\\raggedright}"
770 elif alignment == "right":
771 vval = ">{\\raggedleft}"
774 vval += "V{\\linewidth}"
776 document.body[col_line] = document.body[col_line][:-1] + " special=\"" + vval + "\">"
777 # ERT newlines and linebreaks (since LyX < 2.4 automatically inserts parboxes
778 # with newlines, and we do not want that)
780 endcell = find_token(document.body, "</cell>", begcell)
782 nl = find_token(document.body, "\\begin_inset Newline newline", begcell, endcell)
784 nl = find_token(document.body, "\\begin_inset Newline linebreak", begcell, endcell)
788 nle = find_end_of_inset(document.body, nl)
789 del(document.body[nle:nle+1])
791 document.body[nl:nl+1] = put_cmd_in_ert("\\linebreak{}")
793 document.body[nl:nl+1] = put_cmd_in_ert("\\\\")
799 if needarray == True:
800 add_to_preamble(document, ["\\usepackage{array}"])
801 if needvarwidth == True:
802 add_to_preamble(document, ["\\usepackage{varwidth}"])
805 def revert_bibencoding(document):
806 " Revert bibliography encoding "
810 i = find_token(document.header, "\\cite_engine", 0)
812 document.warning("Malformed document! Missing \\cite_engine")
814 engine = get_value(document.header, "\\cite_engine", i)
818 if engine in ["biblatex", "biblatex-natbib"]:
821 # Map lyx to latex encoding names
825 "armscii8" : "armscii8",
826 "iso8859-1" : "latin1",
827 "iso8859-2" : "latin2",
828 "iso8859-3" : "latin3",
829 "iso8859-4" : "latin4",
830 "iso8859-5" : "iso88595",
831 "iso8859-6" : "8859-6",
832 "iso8859-7" : "iso-8859-7",
833 "iso8859-8" : "8859-8",
834 "iso8859-9" : "latin5",
835 "iso8859-13" : "latin7",
836 "iso8859-15" : "latin9",
837 "iso8859-16" : "latin10",
838 "applemac" : "applemac",
840 "cp437de" : "cp437de",
857 "utf8-platex" : "utf8",
864 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
867 j = find_end_of_inset(document.body, i)
869 document.warning("Can't find end of bibtex inset at line %d!!" %(i))
872 encoding = get_quoted_value(document.body, "encoding", i, j)
876 # remove encoding line
877 k = find_token(document.body, "encoding", i, j)
880 if encoding == "default":
883 # Re-find inset end line
884 j = find_end_of_inset(document.body, i)
887 h = find_token(document.header, "\\biblio_options", 0)
889 biblio_options = get_value(document.header, "\\biblio_options", h)
890 if not "bibencoding" in biblio_options:
891 document.header[h] += ",bibencoding=%s" % encodings[encoding]
893 bs = find_token(document.header, "\\biblatex_bibstyle", 0)
895 # this should not happen
896 document.warning("Malformed LyX document! No \\biblatex_bibstyle header found!")
898 document.header[bs-1 : bs-1] = ["\\biblio_options bibencoding=" + encodings[encoding]]
900 document.body[j+1:j+1] = put_cmd_in_ert("\\egroup")
901 document.body[i:i] = put_cmd_in_ert("\\bgroup\\inputencoding{" + encodings[encoding] + "}")
907 def convert_vcsinfo(document):
908 " Separate vcs Info inset from buffer Info inset. "
911 "vcs-revision" : "revision",
912 "vcs-tree-revision" : "tree-revision",
913 "vcs-author" : "author",
919 i = find_token(document.body, "\\begin_inset Info", i)
922 j = find_end_of_inset(document.body, i + 1)
924 document.warning("Malformed LyX document: Could not find end of Info inset.")
927 tp = find_token(document.body, 'type', i, j)
928 tpv = get_quoted_value(document.body, "type", tp)
932 arg = find_token(document.body, 'arg', i, j)
933 argv = get_quoted_value(document.body, "arg", arg)
934 if argv not in list(types.keys()):
937 document.body[tp] = "type \"vcs\""
938 document.body[arg] = "arg \"" + types[argv] + "\""
942 def revert_vcsinfo(document):
943 " Merge vcs Info inset to buffer Info inset. "
945 args = ["revision", "tree-revision", "author", "time", "date" ]
948 i = find_token(document.body, "\\begin_inset Info", i)
951 j = find_end_of_inset(document.body, i + 1)
953 document.warning("Malformed LyX document: Could not find end of Info inset.")
956 tp = find_token(document.body, 'type', i, j)
957 tpv = get_quoted_value(document.body, "type", tp)
961 arg = find_token(document.body, 'arg', i, j)
962 argv = get_quoted_value(document.body, "arg", arg)
964 document.warning("Malformed Info inset. Invalid vcs arg.")
967 document.body[tp] = "type \"buffer\""
968 document.body[arg] = "arg \"vcs-" + argv + "\""
972 def revert_dateinfo(document):
973 " Revert date info insets to static text. "
975 # FIXME This currently only considers the main language and uses the system locale
976 # Ideally, it should honor context languages and switch the locale accordingly.
978 # The date formats for each language using strftime syntax:
979 # long, short, loclong, locmedium, locshort
981 "afrikaans" : ["%A, %d %B %Y", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y/%m/%d"],
982 "albanian" : ["%A, %d %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
983 "american" : ["%A, %B %d, %Y", "%m/%d/%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
984 "amharic" : ["%A ፣%d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
985 "ancientgreek" : ["%A, %d %B %Y", "%d %b %Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
986 "arabic_arabi" : ["%A، %d %B، %Y", "%d/%m/%Y", "%d %B، %Y", "%d/%m/%Y", "%d/%m/%Y"],
987 "arabic_arabtex" : ["%A، %d %B، %Y", "%d/%m/%Y", "%d %B، %Y", "%d/%m/%Y", "%d/%m/%Y"],
988 "armenian" : ["%Y թ. %B %d, %A", "%d.%m.%y", "%d %B، %Y", "%d %b، %Y", "%d/%m/%Y"],
989 "asturian" : ["%A, %d %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d %b %Y", "%d/%m/%Y"],
990 "australian" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
991 "austrian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
992 "bahasa" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
993 "bahasam" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
994 "basque" : ["%Y(e)ko %B %d, %A", "%y/%m/%d", "%Y %B %d", "%Y %b %d", "%Y/%m/%d"],
995 "belarusian" : ["%A, %d %B %Y г.", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
996 "bosnian" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%Y-%m-%d"],
997 "brazilian" : ["%A, %d de %B de %Y", "%d/%m/%Y", "%d de %B de %Y", "%d de %b de %Y", "%d/%m/%Y"],
998 "breton" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
999 "british" : ["%A, %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1000 "bulgarian" : ["%A, %d %B %Y г.", "%d.%m.%y г.", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
1001 "canadian" : ["%A, %B %d, %Y", "%Y-%m-%d", "%B %d, %Y", "%d %b %Y", "%Y-%m-%d"],
1002 "canadien" : ["%A %d %B %Y", "%y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
1003 "catalan" : ["%A, %d %B de %Y", "%d/%m/%y", "%d / %B / %Y", "%d / %b / %Y", "%d/%m/%Y"],
1004 "chinese-simplified" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y-%m-%d", "%y-%m-%d"],
1005 "chinese-traditional" : ["%Y年%m月%d日 %A", "%Y/%m/%d", "%Y年%m月%d日", "%Y年%m月%d日", "%y年%m月%d日"],
1006 "coptic" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
1007 "croatian" : ["%A, %d. %B %Y.", "%d. %m. %Y.", "%d. %B %Y.", "%d. %b. %Y.", "%d.%m.%Y."],
1008 "czech" : ["%A %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b. %Y", "%d.%m.%Y"],
1009 "danish" : ["%A den %d. %B %Y", "%d/%m/%Y", "%d. %B %Y", "%d. %b %Y", "%d/%m/%Y"],
1010 "divehi" : ["%Y %B %d, %A", "%Y-%m-%d", "%Y %B %d", "%Y %b %d", "%d/%m/%Y"],
1011 "dutch" : ["%A %d %B %Y", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1012 "english" : ["%A, %B %d, %Y", "%m/%d/%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
1013 "esperanto" : ["%A, %d %B %Y", "%d %b %Y", "la %d de %B %Y", "la %d de %b %Y", "%m/%d/%Y"],
1014 "estonian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
1015 "farsi" : ["%A %d %B %Y", "%Y/%m/%d", "%d %B %Y", "%d %b %Y", "%Y/%m/%d"],
1016 "finnish" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1017 "french" : ["%A %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1018 "friulan" : ["%A %d di %B dal %Y", "%d/%m/%y", "%d di %B dal %Y", "%d di %b dal %Y", "%d/%m/%Y"],
1019 "galician" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d de %b de %Y", "%d/%m/%Y"],
1020 "georgian" : ["%A, %d %B, %Y", "%d.%m.%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
1021 "german" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1022 "german-ch" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1023 "german-ch-old" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1024 "greek" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1025 "hebrew" : ["%A, %d ב%B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1026 "hindi" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1027 "icelandic" : ["%A, %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1028 "interlingua" : ["%Y %B %d, %A", "%Y-%m-%d", "le %d de %B %Y", "le %d de %b %Y", "%Y-%m-%d"],
1029 "irish" : ["%A %d %B %Y", "%d/%m/%Y", "%d. %B %Y", "%d. %b %Y", "%d/%m/%Y"],
1030 "italian" : ["%A %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d/%b/%Y", "%d/%m/%Y"],
1031 "japanese" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y/%m/%d", "%y/%m/%d"],
1032 "japanese-cjk" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y/%m/%d", "%y/%m/%d"],
1033 "kannada" : ["%A, %B %d, %Y", "%d/%m/%y", "%d %B %Y", "%d %B %Y", "%d-%m-%Y"],
1034 "kazakh" : ["%Y ж. %d %B, %A", "%d.%m.%y", "%d %B %Y", "%d %B %Y", "%Y-%d-%m"],
1035 "khmer" : ["%A %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %B %Y", "%d/%m/%Y"],
1036 "korean" : ["%Y년 %m월 %d일 %A", "%y. %m. %d.", "%Y년 %m월 %d일", "%Y. %m. %d.", "%y. %m. %d."],
1037 "kurmanji" : ["%A, %d %B %Y", "%d %b %Y", "%d. %B %Y", "%d. %m. %Y", "%Y-%m-%d"],
1038 "lao" : ["%A ທີ %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %B %Y", "%d/%m/%Y"],
1039 "latin" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
1040 "latvian" : ["%A, %Y. gada %d. %B", "%d.%m.%y", "%Y. gada %d. %B", "%Y. gada %d. %b", "%d.%m.%Y"],
1041 "lithuanian" : ["%Y m. %B %d d., %A", "%Y-%m-%d", "%Y m. %B %d d.", "%Y m. %B %d d.", "%Y-%m-%d"],
1042 "lowersorbian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
1043 "macedonian" : ["%A, %d %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
1044 "magyar" : ["%Y. %B %d., %A", "%Y. %m. %d.", "%Y. %B %d.", "%Y. %b %d.", "%Y.%m.%d."],
1045 "malayalam" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1046 "marathi" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1047 "mongolian" : ["%A, %Y оны %m сарын %d", "%Y-%m-%d", "%Y оны %m сарын %d", "%d-%m-%Y", "%d-%m-%Y"],
1048 "naustrian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1049 "newzealand" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1050 "ngerman" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1051 "norsk" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1052 "nynorsk" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1053 "occitan" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1054 "piedmontese" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
1055 "polish" : ["%A, %d %B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
1056 "polutonikogreek" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1057 "portuguese" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d de %b de %Y", "%Y/%m/%d"],
1058 "romanian" : ["%A, %d %B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
1059 "romansh" : ["%A, ils %d da %B %Y", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
1060 "russian" : ["%A, %d %B %Y г.", "%d.%m.%Y", "%d %B %Y г.", "%d %b %Y г.", "%d.%m.%Y"],
1061 "samin" : ["%Y %B %d, %A", "%Y-%m-%d", "%B %d. b. %Y", "%b %d. b. %Y", "%d.%m.%Y"],
1062 "sanskrit" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1063 "scottish" : ["%A, %dmh %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1064 "serbian" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1065 "serbian-latin" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1066 "slovak" : ["%A, %d. %B %Y", "%d. %m. %Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1067 "slovene" : ["%A, %d. %B %Y", "%d. %m. %y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1068 "spanish" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B %de %Y", "%d %b %Y", "%d/%m/%Y"],
1069 "spanish-mexico" : ["%A, %d de %B %de %Y", "%d/%m/%y", "%d de %B de %Y", "%d %b %Y", "%d/%m/%Y"],
1070 "swedish" : ["%A %d %B %Y", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
1071 "syriac" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1072 "tamil" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1073 "telugu" : ["%d, %B %Y, %A", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1074 "thai" : ["%Aที่ %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1075 "tibetan" : ["%Y %Bའི་ཚེས་%d, %A", "%Y-%m-%d", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
1076 "turkish" : ["%d %B %Y %A", "%d.%m.%Y", "%d %B %Y", "%d.%b.%Y", "%d.%m.%Y"],
1077 "turkmen" : ["%d %B %Y %A", "%d.%m.%Y", "%Y ý. %B %d", "%d.%m.%Y ý.", "%d.%m.%y ý."],
1078 "ukrainian" : ["%A, %d %B %Y р.", "%d.%m.%y", "%d %B %Y", "%d %m %Y", "%d.%m.%Y"],
1079 "uppersorbian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
1080 "urdu" : ["%A، %d %B، %Y", "%d/%m/%y", "%d %B, %Y", "%d %b %Y", "%d/%m/%Y"],
1081 "vietnamese" : ["%A, %d %B, %Y", "%d/%m/%Y", "%d tháng %B %Y", "%d-%m-%Y", "%d/%m/%Y"],
1082 "welsh" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1085 types = ["date", "fixdate", "moddate" ]
1086 lang = get_value(document.header, "\\language")
1088 document.warning("Malformed LyX document! No \\language header found!")
1093 i = find_token(document.body, "\\begin_inset Info", i)
1096 j = find_end_of_inset(document.body, i + 1)
1098 document.warning("Malformed LyX document: Could not find end of Info inset.")
1101 tp = find_token(document.body, 'type', i, j)
1102 tpv = get_quoted_value(document.body, "type", tp)
1103 if tpv not in types:
1106 arg = find_token(document.body, 'arg', i, j)
1107 argv = get_quoted_value(document.body, "arg", arg)
1110 if tpv == "fixdate":
1111 datecomps = argv.split('@')
1112 if len(datecomps) > 1:
1114 isodate = datecomps[1]
1115 m = re.search('(\d\d\d\d)-(\d\d)-(\d\d)', isodate)
1117 dte = date(int(m.group(1)), int(m.group(2)), int(m.group(3)))
1118 # FIXME if we had the path to the original document (not the one in the tmp dir),
1119 # we could use the mtime.
1120 # elif tpv == "moddate":
1121 # dte = date.fromtimestamp(os.path.getmtime(document.dir))
1124 result = dte.isodate()
1125 elif argv == "long":
1126 result = dte.strftime(dateformats[lang][0])
1127 elif argv == "short":
1128 result = dte.strftime(dateformats[lang][1])
1129 elif argv == "loclong":
1130 result = dte.strftime(dateformats[lang][2])
1131 elif argv == "locmedium":
1132 result = dte.strftime(dateformats[lang][3])
1133 elif argv == "locshort":
1134 result = dte.strftime(dateformats[lang][4])
1136 fmt = argv.replace("MMMM", "%b").replace("MMM", "%b").replace("MM", "%m").replace("M", "%m")
1137 fmt = fmt.replace("yyyy", "%Y").replace("yy", "%y")
1138 fmt = fmt.replace("dddd", "%A").replace("ddd", "%a").replace("dd", "%d")
1139 fmt = re.sub('[^\'%]d', '%d', fmt)
1140 fmt = fmt.replace("'", "")
1141 result = dte.strftime(fmt)
1142 if sys.version_info < (3,0):
1143 # In Python 2, datetime module works with binary strings,
1144 # our dateformat strings are utf8-encoded:
1145 result = result.decode('utf-8')
1146 document.body[i : j+1] = [result]
1150 def revert_timeinfo(document):
1151 " Revert time info insets to static text. "
1153 # FIXME This currently only considers the main language and uses the system locale
1154 # Ideally, it should honor context languages and switch the locale accordingly.
1155 # Also, the time object is "naive", i.e., it does not know of timezones (%Z will
1158 # The time formats for each language using strftime syntax:
1161 "afrikaans" : ["%H:%M:%S %Z", "%H:%M"],
1162 "albanian" : ["%I:%M:%S %p, %Z", "%I:%M %p"],
1163 "american" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1164 "amharic" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1165 "ancientgreek" : ["%H:%M:%S %Z", "%H:%M:%S"],
1166 "arabic_arabi" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1167 "arabic_arabtex" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1168 "armenian" : ["%H:%M:%S %Z", "%H:%M"],
1169 "asturian" : ["%H:%M:%S %Z", "%H:%M"],
1170 "australian" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1171 "austrian" : ["%H:%M:%S %Z", "%H:%M"],
1172 "bahasa" : ["%H.%M.%S %Z", "%H.%M"],
1173 "bahasam" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1174 "basque" : ["%H:%M:%S (%Z)", "%H:%M"],
1175 "belarusian" : ["%H:%M:%S, %Z", "%H:%M"],
1176 "bosnian" : ["%H:%M:%S %Z", "%H:%M"],
1177 "brazilian" : ["%H:%M:%S %Z", "%H:%M"],
1178 "breton" : ["%H:%M:%S %Z", "%H:%M"],
1179 "british" : ["%H:%M:%S %Z", "%H:%M"],
1180 "bulgarian" : ["%H:%M:%S %Z", "%H:%M"],
1181 "canadian" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1182 "canadien" : ["%H:%M:%S %Z", "%H h %M"],
1183 "catalan" : ["%H:%M:%S %Z", "%H:%M"],
1184 "chinese-simplified" : ["%Z %p%I:%M:%S", "%p%I:%M"],
1185 "chinese-traditional" : ["%p%I:%M:%S [%Z]", "%p%I:%M"],
1186 "coptic" : ["%H:%M:%S %Z", "%H:%M:%S"],
1187 "croatian" : ["%H:%M:%S (%Z)", "%H:%M"],
1188 "czech" : ["%H:%M:%S %Z", "%H:%M"],
1189 "danish" : ["%H.%M.%S %Z", "%H.%M"],
1190 "divehi" : ["%H:%M:%S %Z", "%H:%M"],
1191 "dutch" : ["%H:%M:%S %Z", "%H:%M"],
1192 "english" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1193 "esperanto" : ["%H:%M:%S %Z", "%H:%M:%S"],
1194 "estonian" : ["%H:%M:%S %Z", "%H:%M"],
1195 "farsi" : ["%H:%M:%S (%Z)", "%H:%M"],
1196 "finnish" : ["%H.%M.%S %Z", "%H.%M"],
1197 "french" : ["%H:%M:%S %Z", "%H:%M"],
1198 "friulan" : ["%H:%M:%S %Z", "%H:%M"],
1199 "galician" : ["%H:%M:%S %Z", "%H:%M"],
1200 "georgian" : ["%H:%M:%S %Z", "%H:%M"],
1201 "german" : ["%H:%M:%S %Z", "%H:%M"],
1202 "german-ch" : ["%H:%M:%S %Z", "%H:%M"],
1203 "german-ch-old" : ["%H:%M:%S %Z", "%H:%M"],
1204 "greek" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1205 "hebrew" : ["%H:%M:%S %Z", "%H:%M"],
1206 "hindi" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1207 "icelandic" : ["%H:%M:%S %Z", "%H:%M"],
1208 "interlingua" : ["%H:%M:%S %Z", "%H:%M"],
1209 "irish" : ["%H:%M:%S %Z", "%H:%M"],
1210 "italian" : ["%H:%M:%S %Z", "%H:%M"],
1211 "japanese" : ["%H時%M分%S秒 %Z", "%H:%M"],
1212 "japanese-cjk" : ["%H時%M分%S秒 %Z", "%H:%M"],
1213 "kannada" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1214 "kazakh" : ["%H:%M:%S %Z", "%H:%M"],
1215 "khmer" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1216 "korean" : ["%p %I시%M분 %S초 %Z", "%p %I:%M"],
1217 "kurmanji" : ["%H:%M:%S %Z", "%H:%M:%S"],
1218 "lao" : ["%H ໂມງ%M ນາທີ %S ວິນາທີ %Z", "%H:%M"],
1219 "latin" : ["%H:%M:%S %Z", "%H:%M:%S"],
1220 "latvian" : ["%H:%M:%S %Z", "%H:%M"],
1221 "lithuanian" : ["%H:%M:%S %Z", "%H:%M"],
1222 "lowersorbian" : ["%H:%M:%S %Z", "%H:%M"],
1223 "macedonian" : ["%H:%M:%S %Z", "%H:%M"],
1224 "magyar" : ["%H:%M:%S %Z", "%H:%M"],
1225 "malayalam" : ["%p %I:%M:%S %Z", "%p %I:%M"],
1226 "marathi" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1227 "mongolian" : ["%H:%M:%S %Z", "%H:%M"],
1228 "naustrian" : ["%H:%M:%S %Z", "%H:%M"],
1229 "newzealand" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1230 "ngerman" : ["%H:%M:%S %Z", "%H:%M"],
1231 "norsk" : ["%H:%M:%S %Z", "%H:%M"],
1232 "nynorsk" : ["kl. %H:%M:%S %Z", "%H:%M"],
1233 "occitan" : ["%H:%M:%S %Z", "%H:%M"],
1234 "piedmontese" : ["%H:%M:%S %Z", "%H:%M:%S"],
1235 "polish" : ["%H:%M:%S %Z", "%H:%M"],
1236 "polutonikogreek" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1237 "portuguese" : ["%H:%M:%S %Z", "%H:%M"],
1238 "romanian" : ["%H:%M:%S %Z", "%H:%M"],
1239 "romansh" : ["%H:%M:%S %Z", "%H:%M"],
1240 "russian" : ["%H:%M:%S %Z", "%H:%M"],
1241 "samin" : ["%H:%M:%S %Z", "%H:%M"],
1242 "sanskrit" : ["%H:%M:%S %Z", "%H:%M"],
1243 "scottish" : ["%H:%M:%S %Z", "%H:%M"],
1244 "serbian" : ["%H:%M:%S %Z", "%H:%M"],
1245 "serbian-latin" : ["%H:%M:%S %Z", "%H:%M"],
1246 "slovak" : ["%H:%M:%S %Z", "%H:%M"],
1247 "slovene" : ["%H:%M:%S %Z", "%H:%M"],
1248 "spanish" : ["%H:%M:%S (%Z)", "%H:%M"],
1249 "spanish-mexico" : ["%H:%M:%S %Z", "%H:%M"],
1250 "swedish" : ["kl. %H:%M:%S %Z", "%H:%M"],
1251 "syriac" : ["%H:%M:%S %Z", "%H:%M"],
1252 "tamil" : ["%p %I:%M:%S %Z", "%p %I:%M"],
1253 "telugu" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1254 "thai" : ["%H นาฬิกา %M นาที %S วินาที %Z", "%H:%M"],
1255 "tibetan" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1256 "turkish" : ["%H:%M:%S %Z", "%H:%M"],
1257 "turkmen" : ["%H:%M:%S %Z", "%H:%M"],
1258 "ukrainian" : ["%H:%M:%S %Z", "%H:%M"],
1259 "uppersorbian" : ["%H:%M:%S %Z", "%H:%M hodź."],
1260 "urdu" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1261 "vietnamese" : ["%H:%M:%S %Z", "%H:%M"],
1262 "welsh" : ["%H:%M:%S %Z", "%H:%M"]
1265 types = ["time", "fixtime", "modtime" ]
1267 i = find_token(document.header, "\\language", 0)
1269 # this should not happen
1270 document.warning("Malformed LyX document! No \\language header found!")
1272 lang = get_value(document.header, "\\language", i)
1276 i = find_token(document.body, "\\begin_inset Info", i)
1279 j = find_end_of_inset(document.body, i + 1)
1281 document.warning("Malformed LyX document: Could not find end of Info inset.")
1284 tp = find_token(document.body, 'type', i, j)
1285 tpv = get_quoted_value(document.body, "type", tp)
1286 if tpv not in types:
1289 arg = find_token(document.body, 'arg', i, j)
1290 argv = get_quoted_value(document.body, "arg", arg)
1292 dtme = datetime.now()
1294 if tpv == "fixtime":
1295 timecomps = argv.split('@')
1296 if len(timecomps) > 1:
1298 isotime = timecomps[1]
1299 m = re.search('(\d\d):(\d\d):(\d\d)', isotime)
1301 tme = time(int(m.group(1)), int(m.group(2)), int(m.group(3)))
1303 m = re.search('(\d\d):(\d\d)', isotime)
1305 tme = time(int(m.group(1)), int(m.group(2)))
1306 # FIXME if we had the path to the original document (not the one in the tmp dir),
1307 # we could use the mtime.
1308 # elif tpv == "moddate":
1309 # dte = date.fromtimestamp(os.path.getmtime(document.dir))
1312 result = tme.isoformat()
1313 elif argv == "long":
1314 result = tme.strftime(timeformats[lang][0])
1315 elif argv == "short":
1316 result = tme.strftime(timeformats[lang][1])
1318 fmt = argv.replace("HH", "%H").replace("H", "%H").replace("hh", "%I").replace("h", "%I")
1319 fmt = fmt.replace("mm", "%M").replace("m", "%M").replace("ss", "%S").replace("s", "%S")
1320 fmt = fmt.replace("zzz", "%f").replace("z", "%f").replace("t", "%Z")
1321 fmt = fmt.replace("AP", "%p").replace("ap", "%p").replace("A", "%p").replace("a", "%p")
1322 fmt = fmt.replace("'", "")
1323 result = dte.strftime(fmt)
1324 document.body[i : j+1] = result
1328 def revert_namenoextinfo(document):
1329 " Merge buffer Info inset type name-noext to name. "
1333 i = find_token(document.body, "\\begin_inset Info", i)
1336 j = find_end_of_inset(document.body, i + 1)
1338 document.warning("Malformed LyX document: Could not find end of Info inset.")
1341 tp = find_token(document.body, 'type', i, j)
1342 tpv = get_quoted_value(document.body, "type", tp)
1346 arg = find_token(document.body, 'arg', i, j)
1347 argv = get_quoted_value(document.body, "arg", arg)
1348 if argv != "name-noext":
1351 document.body[arg] = "arg \"name\""
1355 def revert_l7ninfo(document):
1356 " Revert l7n Info inset to text. "
1360 i = find_token(document.body, "\\begin_inset Info", i)
1363 j = find_end_of_inset(document.body, i + 1)
1365 document.warning("Malformed LyX document: Could not find end of Info inset.")
1368 tp = find_token(document.body, 'type', i, j)
1369 tpv = get_quoted_value(document.body, "type", tp)
1373 arg = find_token(document.body, 'arg', i, j)
1374 argv = get_quoted_value(document.body, "arg", arg)
1375 # remove trailing colons, menu accelerator (|...) and qt accelerator (&), while keeping literal " & "
1376 argv = argv.rstrip(':').split('|')[0].replace(" & ", "</amp;>").replace("&", "").replace("</amp;>", " & ")
1377 document.body[i : j+1] = argv
1381 def revert_listpargs(document):
1382 " Reverts listpreamble arguments to TeX-code "
1385 i = find_token(document.body, "\\begin_inset Argument listpreamble:", i)
1388 j = find_end_of_inset(document.body, i)
1389 # Find containing paragraph layout
1390 parent = get_containing_layout(document.body, i)
1392 document.warning("Malformed LyX document: Can't find parent paragraph layout")
1396 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
1397 endPlain = find_end_of_layout(document.body, beginPlain)
1398 content = document.body[beginPlain + 1 : endPlain]
1399 del document.body[i:j+1]
1400 subst = ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Plain Layout",
1401 "{"] + content + ["}", "\\end_layout", "", "\\end_inset", ""]
1402 document.body[parbeg : parbeg] = subst
1406 def revert_lformatinfo(document):
1407 " Revert layout format Info inset to text. "
1411 i = find_token(document.body, "\\begin_inset Info", i)
1414 j = find_end_of_inset(document.body, i + 1)
1416 document.warning("Malformed LyX document: Could not find end of Info inset.")
1419 tp = find_token(document.body, 'type', i, j)
1420 tpv = get_quoted_value(document.body, "type", tp)
1421 if tpv != "lyxinfo":
1424 arg = find_token(document.body, 'arg', i, j)
1425 argv = get_quoted_value(document.body, "arg", arg)
1426 if argv != "layoutformat":
1430 document.body[i : j+1] = "69"
1434 def convert_hebrew_parentheses(document):
1435 """ Swap opening/closing parentheses in Hebrew text.
1437 Up to LyX 2.4, "(" was used as closing parenthesis and
1438 ")" as opening parenthesis for Hebrew in the LyX source.
1440 # print("convert hebrew parentheses")
1441 current_languages = [document.language]
1442 for i, line in enumerate(document.body):
1443 if line.startswith('\\lang '):
1444 current_languages[-1] = line.lstrip('\\lang ')
1445 elif line.startswith('\\begin_layout'):
1446 current_languages.append(current_languages[-1])
1447 # print (line, current_languages[-1])
1448 elif line.startswith('\\end_layout'):
1449 current_languages.pop()
1450 elif current_languages[-1] == 'hebrew' and not line.startswith('\\'):
1451 document.body[i] = line.replace('(','\x00').replace(')','(').replace('\x00',')')
1454 def revert_hebrew_parentheses(document):
1455 " Store parentheses in Hebrew text reversed"
1456 # This only exists to keep the convert/revert naming convention
1457 convert_hebrew_parentheses(document)
1460 def revert_malayalam(document):
1461 " Set the document language to English but assure Malayalam output "
1463 revert_language(document, "malayalam", "", "malayalam")
1466 def revert_soul(document):
1467 " Revert soul module flex insets to ERT "
1469 flexes = ["Spaceletters", "Strikethrough", "Underline", "Highlight", "Capitalize"]
1472 i = find_token(document.body, "\\begin_inset Flex %s" % flex, 0)
1474 add_to_preamble(document, ["\\usepackage{soul}"])
1476 i = find_token(document.body, "\\begin_inset Flex Highlight", 0)
1478 add_to_preamble(document, ["\\usepackage{color}"])
1480 revert_flex_inset(document.body, "Spaceletters", "\\so")
1481 revert_flex_inset(document.body, "Strikethrough", "\\st")
1482 revert_flex_inset(document.body, "Underline", "\\ul")
1483 revert_flex_inset(document.body, "Highlight", "\\hl")
1484 revert_flex_inset(document.body, "Capitalize", "\\caps")
1487 def revert_tablestyle(document):
1488 " Remove tablestyle params "
1491 i = find_token(document.header, "\\tablestyle", 0)
1493 del document.header[i]
1496 def revert_bibfileencodings(document):
1497 " Revert individual Biblatex bibliography encodings "
1501 i = find_token(document.header, "\\cite_engine", 0)
1503 document.warning("Malformed document! Missing \\cite_engine")
1505 engine = get_value(document.header, "\\cite_engine", i)
1509 if engine in ["biblatex", "biblatex-natbib"]:
1512 # Map lyx to latex encoding names
1516 "armscii8" : "armscii8",
1517 "iso8859-1" : "latin1",
1518 "iso8859-2" : "latin2",
1519 "iso8859-3" : "latin3",
1520 "iso8859-4" : "latin4",
1521 "iso8859-5" : "iso88595",
1522 "iso8859-6" : "8859-6",
1523 "iso8859-7" : "iso-8859-7",
1524 "iso8859-8" : "8859-8",
1525 "iso8859-9" : "latin5",
1526 "iso8859-13" : "latin7",
1527 "iso8859-15" : "latin9",
1528 "iso8859-16" : "latin10",
1529 "applemac" : "applemac",
1531 "cp437de" : "cp437de",
1539 "cp1250" : "cp1250",
1540 "cp1251" : "cp1251",
1541 "cp1252" : "cp1252",
1542 "cp1255" : "cp1255",
1543 "cp1256" : "cp1256",
1544 "cp1257" : "cp1257",
1545 "koi8-r" : "koi8-r",
1546 "koi8-u" : "koi8-u",
1548 "utf8-platex" : "utf8",
1555 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1558 j = find_end_of_inset(document.body, i)
1560 document.warning("Can't find end of bibtex inset at line %d!!" %(i))
1563 encodings = get_quoted_value(document.body, "file_encodings", i, j)
1567 bibfiles = get_quoted_value(document.body, "bibfiles", i, j).split(",")
1568 opts = get_quoted_value(document.body, "biblatexopts", i, j)
1569 if len(bibfiles) == 0:
1570 document.warning("Bibtex inset at line %d does not have a bibfile!" %(i))
1571 # remove encoding line
1572 k = find_token(document.body, "file_encodings", i, j)
1574 del document.body[k]
1575 # Re-find inset end line
1576 j = find_end_of_inset(document.body, i)
1578 enclist = encodings.split("\t")
1581 ppp = pp.split(" ", 1)
1582 encmap[ppp[0]] = ppp[1]
1583 for bib in bibfiles:
1584 pr = "\\addbibresource"
1585 if bib in encmap.keys():
1586 pr += "[bibencoding=" + encmap[bib] + "]"
1587 pr += "{" + bib + "}"
1588 add_to_preamble(document, [pr])
1589 # Insert ERT \\printbibliography and wrap bibtex inset to a Note
1590 pcmd = "printbibliography"
1592 pcmd += "[" + opts + "]"
1593 repl = ["\\begin_inset ERT", "status open", "", "\\begin_layout Plain Layout",\
1594 "", "", "\\backslash", pcmd, "\\end_layout", "", "\\end_inset", "", "",\
1595 "\\end_layout", "", "\\begin_layout Standard", "\\begin_inset Note Note",\
1596 "status open", "", "\\begin_layout Plain Layout" ]
1597 repl += document.body[i:j+1]
1598 repl += ["", "\\end_layout", "", "\\end_inset", "", ""]
1599 document.body[i:j+1] = repl
1605 def revert_cmidruletrimming(document):
1606 " Remove \\cmidrule trimming "
1608 # FIXME: Revert to TeX code?
1611 # first, let's find out if we need to do anything
1612 i = find_token(document.body, '<cell ', i)
1615 j = document.body[i].find('trim="')
1619 rgx = re.compile(r' (bottom|top)line[lr]trim="true"')
1620 # remove trim option
1621 document.body[i] = rgx.sub('', document.body[i])
1627 r'### Inserted by lyx2lyx (ruby inset) ###',
1628 r'InsetLayout Flex:Ruby',
1629 r' LyxType charstyle',
1630 r' LatexType command',
1634 r' HTMLInnerTag rb',
1635 r' HTMLInnerAttr ""',
1637 r' LabelString "Ruby"',
1638 r' Decoration Conglomerate',
1640 r' \ifdefined\kanjiskip',
1641 r' \IfFileExists{okumacro.sty}{\usepackage{okumacro}}{}',
1642 r' \else \ifdefined\luatexversion',
1643 r' \usepackage{luatexja-ruby}',
1644 r' \else \ifdefined\XeTeXversion',
1645 r' \usepackage{ruby}%',
1647 r' \providecommand{\ruby}[2]{\shortstack{\tiny #2\\#1}}',
1649 r' Argument post:1',
1650 r' LabelString "ruby text"',
1651 r' MenuString "Ruby Text|R"',
1652 r' Tooltip "Reading aid (ruby, furigana) for Chinese characters."',
1653 r' Decoration Conglomerate',
1665 def convert_ruby_module(document):
1666 " Use ruby module instead of local module definition "
1667 if document.del_local_layout(ruby_inset_def):
1668 document.add_module("ruby")
1670 def revert_ruby_module(document):
1671 " Replace ruby module with local module definition "
1672 if document.del_module("ruby"):
1673 document.append_local_layout(ruby_inset_def)
1676 def convert_utf8_japanese(document):
1677 " Use generic utf8 with Japanese documents."
1678 lang = get_value(document.header, "\\language")
1679 if not lang.startswith("japanese"):
1681 inputenc = get_value(document.header, "\\inputencoding")
1682 if ((lang == "japanese" and inputenc == "utf8-platex")
1683 or (lang == "japanese-cjk" and inputenc == "utf8-cjk")):
1684 document.set_parameter("inputencoding", "utf8")
1686 def revert_utf8_japanese(document):
1687 " Use Japanese utf8 variants with Japanese documents."
1688 inputenc = get_value(document.header, "\\inputencoding")
1689 if inputenc != "utf8":
1691 lang = get_value(document.header, "\\language")
1692 if lang == "japanese":
1693 document.set_parameter("inputencoding", "utf8-platex")
1694 if lang == "japanese-cjk":
1695 document.set_parameter("inputencoding", "utf8-cjk")
1698 def revert_lineno(document):
1699 " Replace lineno setting with user-preamble code."
1701 options = get_quoted_value(document.header, "\\lineno_options",
1703 if not get_bool_value(document.header, "\\use_lineno", delete=True):
1706 options = "[" + options + "]"
1707 add_to_preamble(document, ["\\usepackage%s{lineno}" % options,
1710 def convert_lineno(document):
1711 " Replace user-preamble code with native lineno support."
1714 j = find_token(document.preamble, "\\linenumbers", 1)
1716 usepkg = re.match(r"\\usepackage(.*){lineno}", document.preamble[j-1])
1719 options = usepkg.group(1).strip("[]")
1720 del(document.preamble[j-1:j+1])
1721 del_token(document.preamble, "% Added by lyx2lyx", j-2, j-1)
1723 k = find_token(document.header, "\\index ")
1725 document.header[k:k] = ["\\use_lineno %d" % use_lineno]
1727 document.header[k:k] = ["\\use_lineno %d" % use_lineno,
1728 "\\lineno_options %s" % options]
1731 def revert_new_languages(document):
1732 """Emulate support for Azerbaijani, Bengali, Church Slavonic, Korean,
1733 and Russian (Petrine orthography)."""
1735 #revert_language(document, lyxname, babelname="", polyglossianame="")
1736 revert_language(document, "azerbaijani", "azerbaijani", "")
1737 revert_language(document, "bengali", "", "bengali")
1738 revert_language(document, "churchslavonic", "", "churchslavonic")
1739 revert_language(document, "oldrussian", "", "russian")
1741 # Korean is already supported via CJK, so leave as-is for Babel
1742 if not get_bool_value(document.header, "\\use_non_tex_fonts"):
1744 langpack = get_value(document.header, "\\language_package")
1745 if langpack not in ("default", "auto"):
1747 if document.language == "korean":
1748 add_to_preamble(document, ["\\usepackage{polyglossia}",
1749 "\\setdefaultlanguage{korean}"])
1750 elif find_token(document.body, "\\lang korean") != -1:
1751 revert_language(document, "korean", "", "korean")
1755 r'### Inserted by lyx2lyx (deprecated ling glosses) ###',
1756 r'InsetLayout Flex:Glosse',
1758 r' LabelString "Gloss (old version)"',
1759 r' MenuString "Gloss (old version)"',
1760 r' LatexType environment',
1761 r' LatexName linggloss',
1762 r' Decoration minimalistic',
1767 r' CustomPars false',
1768 r' ForcePlain true',
1769 r' ParbreakIsNewline true',
1770 r' FreeSpacing true',
1771 r' Requires covington',
1774 r' \@ifundefined{linggloss}{%',
1775 r' \newenvironment{linggloss}[2][]{',
1776 r' \def\glosstr{\glt #1}%',
1778 r' {\glosstr\glend}}{}',
1781 r' ResetsFont true',
1783 r' Decoration conglomerate',
1784 r' LabelString "Translation"',
1785 r' MenuString "Glosse Translation|s"',
1786 r' Tooltip "Add a translation for the glosse"',
1791 glosss_inset_def = [
1792 r'### Inserted by lyx2lyx (deprecated ling glosses) ###',
1793 r'InsetLayout Flex:Tri-Glosse',
1795 r' LabelString "Tri-Gloss (old version)"',
1796 r' MenuString "Tri-Gloss (old version)"',
1797 r' LatexType environment',
1798 r' LatexName lingglosss',
1799 r' Decoration minimalistic',
1804 r' CustomPars false',
1805 r' ForcePlain true',
1806 r' ParbreakIsNewline true',
1807 r' FreeSpacing true',
1809 r' Requires covington',
1812 r' \@ifundefined{lingglosss}{%',
1813 r' \newenvironment{lingglosss}[2][]{',
1814 r' \def\glosstr{\glt #1}%',
1816 r' {\glosstr\glend}}{}',
1818 r' ResetsFont true',
1820 r' Decoration conglomerate',
1821 r' LabelString "Translation"',
1822 r' MenuString "Glosse Translation|s"',
1823 r' Tooltip "Add a translation for the glosse"',
1828 def convert_linggloss(document):
1829 " Move old ling glosses to local layout "
1830 if find_token(document.body, '\\begin_inset Flex Glosse', 0) != -1:
1831 document.append_local_layout(gloss_inset_def)
1832 if find_token(document.body, '\\begin_inset Flex Tri-Glosse', 0) != -1:
1833 document.append_local_layout(glosss_inset_def)
1835 def revert_linggloss(document):
1836 " Revert to old ling gloss definitions "
1837 document.del_local_layout(gloss_inset_def)
1838 document.del_local_layout(glosss_inset_def)
1840 if not "linguistics" in document.get_module_list():
1844 glosses = ("\\begin_inset Flex Interlinear Gloss (2 Lines)", "\\begin_inset Flex Interlinear Gloss (3 Lines)")
1845 for glosse in glosses:
1848 i = find_token(document.body, glosse, i)
1851 j = find_end_of_inset(document.body, i)
1853 document.warning("Malformed LyX document: Can't find end of Gloss inset")
1857 arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
1858 endarg = find_end_of_inset(document.body, arg)
1861 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
1862 if argbeginPlain == -1:
1863 document.warning("Malformed LyX document: Can't find optarg plain Layout")
1866 argendPlain = find_end_of_inset(document.body, argbeginPlain)
1867 optargcontent = document.body[argbeginPlain + 1 : argendPlain - 2]
1869 # remove Arg insets and paragraph, if it only contains this inset
1870 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
1871 del document.body[arg - 1 : endarg + 4]
1873 del document.body[arg : endarg + 1]
1875 arg = find_token(document.body, "\\begin_inset Argument post:1", i, j)
1876 endarg = find_end_of_inset(document.body, arg)
1879 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
1880 if argbeginPlain == -1:
1881 document.warning("Malformed LyX document: Can't find arg 1 plain Layout")
1884 argendPlain = find_end_of_inset(document.body, argbeginPlain)
1885 marg1content = document.body[argbeginPlain + 1 : argendPlain - 2]
1887 # remove Arg insets and paragraph, if it only contains this inset
1888 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
1889 del document.body[arg - 1 : endarg + 4]
1891 del document.body[arg : endarg + 1]
1893 arg = find_token(document.body, "\\begin_inset Argument post:2", i, j)
1894 endarg = find_end_of_inset(document.body, arg)
1897 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
1898 if argbeginPlain == -1:
1899 document.warning("Malformed LyX document: Can't find arg 2 plain Layout")
1902 argendPlain = find_end_of_inset(document.body, argbeginPlain)
1903 marg2content = document.body[argbeginPlain + 1 : argendPlain - 2]
1905 # remove Arg insets and paragraph, if it only contains this inset
1906 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
1907 del document.body[arg - 1 : endarg + 4]
1909 del document.body[arg : endarg + 1]
1911 arg = find_token(document.body, "\\begin_inset Argument post:3", i, j)
1912 endarg = find_end_of_inset(document.body, arg)
1915 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
1916 if argbeginPlain == -1:
1917 document.warning("Malformed LyX document: Can't find arg 3 plain Layout")
1920 argendPlain = find_end_of_inset(document.body, argbeginPlain)
1921 marg3content = document.body[argbeginPlain + 1 : argendPlain - 2]
1923 # remove Arg insets and paragraph, if it only contains this inset
1924 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
1925 del document.body[arg - 1 : endarg + 4]
1927 del document.body[arg : endarg + 1]
1930 if glosse == "\\begin_inset Flex Interlinear Gloss (3 Lines)":
1933 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
1934 endInset = find_end_of_inset(document.body, i)
1935 endPlain = find_token_backwards(document.body, "\\end_layout", endInset)
1936 precontent = put_cmd_in_ert(cmd)
1937 if len(optargcontent) > 0:
1938 precontent += put_cmd_in_ert("[") + optargcontent + put_cmd_in_ert("]")
1939 precontent += put_cmd_in_ert("{")
1941 postcontent = put_cmd_in_ert("}{") + marg1content + put_cmd_in_ert("}{") + marg2content
1942 if cmd == "\\trigloss":
1943 postcontent += put_cmd_in_ert("}{") + marg3content
1944 postcontent += put_cmd_in_ert("}")
1946 document.body[endPlain:endInset + 1] = postcontent
1947 document.body[beginPlain + 1:beginPlain] = precontent
1948 del document.body[i : beginPlain + 1]
1950 document.append_local_layout("Requires covington")
1959 supported_versions = ["2.4.0", "2.4"]
1961 [545, [convert_lst_literalparam]],
1966 [550, [convert_fontenc]],
1973 [557, [convert_vcsinfo]],
1974 [558, [removeFrontMatterStyles]],
1977 [561, [convert_latexFonts]], # Handle dejavu, ibmplex fonts in GUI
1981 [565, [convert_AdobeFonts]], # Handle adobe fonts in GUI
1982 [566, [convert_hebrew_parentheses]],
1988 [572, [convert_notoFonts]], # Added options thin, light, extralight for Noto
1989 [573, [convert_inputencoding_namechange]],
1990 [574, [convert_ruby_module, convert_utf8_japanese]],
1991 [575, [convert_lineno]],
1993 [577, [convert_linggloss]]
1996 revert = [[576, [revert_linggloss]],
1997 [575, [revert_new_languages]],
1998 [574, [revert_lineno]],
1999 [573, [revert_ruby_module, revert_utf8_japanese]],
2000 [572, [revert_inputencoding_namechange]],
2001 [571, [revert_notoFonts]],
2002 [570, [revert_cmidruletrimming]],
2003 [569, [revert_bibfileencodings]],
2004 [568, [revert_tablestyle]],
2005 [567, [revert_soul]],
2006 [566, [revert_malayalam]],
2007 [565, [revert_hebrew_parentheses]],
2008 [564, [revert_AdobeFonts]],
2009 [563, [revert_lformatinfo]],
2010 [562, [revert_listpargs]],
2011 [561, [revert_l7ninfo]],
2012 [560, [revert_latexFonts]], # Handle dejavu, ibmplex fonts in user preamble
2013 [559, [revert_timeinfo, revert_namenoextinfo]],
2014 [558, [revert_dateinfo]],
2015 [557, [addFrontMatterStyles]],
2016 [556, [revert_vcsinfo]],
2017 [555, [revert_bibencoding]],
2018 [554, [revert_vcolumns]],
2019 [553, [revert_stretchcolumn]],
2020 [552, [revert_tuftecite]],
2021 [551, [revert_floatpclass, revert_floatalignment]],
2022 [550, [revert_nospellcheck]],
2023 [549, [revert_fontenc]],
2024 [548, []],# dummy format change
2025 [547, [revert_lscape]],
2026 [546, [revert_xcharter]],
2027 [545, [revert_paratype]],
2028 [544, [revert_lst_literalparam]]
2032 if __name__ == "__main__":