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_token_exact,
31 find_re, get_bool_value,
32 get_containing_layout, get_option_value, get_value, get_quoted_value)
33 # del_value, del_complete_lines,
34 # find_complete_lines, find_end_of,
35 # find_re, find_substring,
36 # get_containing_inset,
37 # is_in_inset, set_bool_value
38 # find_tokens, check_token
40 from lyx2lyx_tools import (put_cmd_in_ert, add_to_preamble, lyx2latex, revert_language, revert_flex_inset)
41 # revert_font_attrs, insert_to_preamble, latex_length
42 # get_ert, lyx2verbatim, length_in_bp, convert_info_insets
43 # revert_flex_inset, hex2ratio, str2bool
45 ####################################################################
46 # Private helper functions
48 def add_preamble_fonts(document, fontmap):
49 " Add collected font-packages with their option to user-preamble"
52 if len(fontmap[pkg]) > 0:
53 xoption = "[" + ",".join(fontmap[pkg]) + "]"
56 preamble = "\\usepackage%s{%s}" % (xoption, pkg)
57 add_to_preamble(document, [preamble])
60 def createkey(pkg, options):
62 return pkg + ':' + "-".join(options)
66 self.fontname = None # key into font2pkgmap
67 self.fonttype = None # roman,sans,typewriter,math
68 self.scaletype = None # None,sf,tt
69 self.scaleopt = None # None, 'scaled', 'scale'
73 self.pkgkey = None # key into pkg2fontmap
76 self.pkgkey = createkey(self.package, self.options)
80 self.font2pkgmap = dict()
81 self.pkg2fontmap = dict()
82 self.pkginmap = dict() # defines, if a map for package exists
84 def expandFontMapping(self, font_list, font_type, scale_type, pkg, scaleopt = None):
85 " Expand fontinfo mapping"
87 # fontlist: list of fontnames, each element
88 # may contain a ','-separated list of needed options
89 # like e.g. 'IBMPlexSansCondensed,condensed'
90 # font_type: one of 'roman', 'sans', 'typewriter', 'math'
91 # scale_type: one of None, 'sf', 'tt'
92 # pkg: package defining the font. Defaults to fontname if None
93 # scaleopt: one of None, 'scale', 'scaled', or some other string
94 # to be used in scale option (e.g. scaled=0.7)
97 fe.fonttype = font_type
98 fe.scaletype = scale_type
101 fe.fontname = font_name
103 fe.scaleopt = scaleopt
105 fe.package = font_name
109 self.font2pkgmap[font_name] = fe
110 if fe.pkgkey in self.pkg2fontmap:
111 # Repeated the same entry? Check content
112 if self.pkg2fontmap[fe.pkgkey] != font_name:
113 document.error("Something is wrong in pkgname+options <-> fontname mapping")
114 self.pkg2fontmap[fe.pkgkey] = font_name
115 self.pkginmap[fe.package] = 1
117 def getfontname(self, pkg, options):
119 pkgkey = createkey(pkg, options)
120 if not pkgkey in self.pkg2fontmap:
122 fontname = self.pkg2fontmap[pkgkey]
123 if not fontname in self.font2pkgmap:
124 document.error("Something is wrong in pkgname+options <-> fontname mapping")
126 if pkgkey == self.font2pkgmap[fontname].pkgkey:
130 def createFontMapping(fontlist):
131 # Create info for known fonts for the use in
132 # convert_latexFonts() and
133 # revert_latexFonts()
135 # * Would be more handy to parse latexFonts file,
136 # but the path to this file is unknown
137 # * For now, add DejaVu and IBMPlex only.
138 # * Expand, if desired
140 for font in fontlist:
142 fm.expandFontMapping(['DejaVuSerif', 'DejaVuSerifCondensed'], "roman", None, None)
143 fm.expandFontMapping(['DejaVuSans','DejaVuSansCondensed'], "sans", "sf", None, "scaled")
144 fm.expandFontMapping(['DejaVuSansMono'], "typewriter", "tt", None, "scaled")
146 fm.expandFontMapping(['IBMPlexSerif', 'IBMPlexSerifThin,thin',
147 'IBMPlexSerifExtraLight,extralight', 'IBMPlexSerifLight,light',
148 'IBMPlexSerifSemibold,semibold'],
149 "roman", None, "plex-serif")
150 fm.expandFontMapping(['IBMPlexSans','IBMPlexSansCondensed,condensed',
151 'IBMPlexSansThin,thin', 'IBMPlexSansExtraLight,extralight',
152 'IBMPlexSansLight,light', 'IBMPlexSansSemibold,semibold'],
153 "sans", "sf", "plex-sans", "scale")
154 fm.expandFontMapping(['IBMPlexMono', 'IBMPlexMonoThin,thin',
155 'IBMPlexMonoExtraLight,extralight', 'IBMPlexMonoLight,light',
156 'IBMPlexMonoSemibold,semibold'],
157 "typewriter", "tt", "plex-mono", "scale")
158 elif font == 'Adobe':
159 fm.expandFontMapping(['ADOBESourceSerifPro'], "roman", None, "sourceserifpro")
160 fm.expandFontMapping(['ADOBESourceSansPro'], "sans", "sf", "sourcesanspro", "scaled")
161 fm.expandFontMapping(['ADOBESourceCodePro'], "typewriter", "tt", "sourcecodepro", "scaled")
163 fm.expandFontMapping(['NotoSerifRegular,regular', 'NotoSerifMedium,medium',
164 'NotoSerifThin,thin', 'NotoSerifLight,light',
165 'NotoSerifExtralight,extralight'],
166 "roman", None, "noto-serif")
167 fm.expandFontMapping(['NotoSansRegular,regular', 'NotoSansMedium,medium',
168 'NotoSansThin,thin', 'NotoSansLight,light',
169 'NotoSansExtralight,extralight'],
170 "sans", "sf", "noto-sans", "scaled")
171 fm.expandFontMapping(['NotoMonoRegular'], "typewriter", "tt", "noto-mono", "scaled")
174 def convert_fonts(document, fm):
175 " Handle font definition to LaTeX "
177 rpkg = re.compile(r'^\\usepackage(\[([^\]]*)\])?\{([^\}]+)\}')
178 rscaleopt = re.compile(r'^scaled?=(.*)')
181 while i < len(document.preamble):
182 i = find_re(document.preamble, rpkg, i)
185 mo = rpkg.search(document.preamble[i])
186 if mo == None or mo.group(2) == None:
189 options = mo.group(2).replace(' ', '').split(",")
193 while o < len(options):
194 mo = rscaleopt.search(options[o])
202 if not pkg in fm.pkginmap:
206 fn = fm.getfontname(pkg, options)
210 del document.preamble[i]
211 fontinfo = fm.font2pkgmap[fn]
212 if fontinfo.scaletype == None:
215 fontscale = "\\font_" + fontinfo.scaletype + "_scale"
216 fontinfo.scaleval = oscale
218 if i > 0 and document.preamble[i-1] == "% Added by lyx2lyx":
219 del document.preamble[i-1]
220 if fontscale != None:
221 j = find_token(document.header, fontscale, 0)
223 val = get_value(document.header, fontscale, j)
227 scale = "%03d" % int(float(oscale) * 100)
228 document.header[j] = fontscale + " " + scale + " " + vals[1]
229 ft = "\\font_" + fontinfo.fonttype
230 j = find_token(document.header, ft, 0)
232 val = get_value(document.header, ft, j)
233 words = val.split() # ! splits also values like '"DejaVu Sans"'
234 words[0] = '"' + fn + '"'
235 document.header[j] = ft + ' ' + ' '.join(words)
237 def revert_fonts(document, fm, fontmap):
238 " Revert native font definition to LaTeX "
239 # fonlist := list of fonts created from the same package
240 # Empty package means that the font-name is the same as the package-name
241 # fontmap (key = package, val += found options) will be filled
242 # and used later in add_preamble_fonts() to be added to user-preamble
244 rfontscale = re.compile(r'^\s*(\\font_(roman|sans|typewriter|math))\s+')
245 rscales = re.compile(r'^\s*(\d+)\s+(\d+)')
247 while i < len(document.header):
248 i = find_re(document.header, rfontscale, i)
251 mo = rfontscale.search(document.header[i])
255 ft = mo.group(1) # 'roman', 'sans', 'typewriter', 'math'
256 val = get_value(document.header, ft, i)
257 words = val.split(' ') # ! splits also values like '"DejaVu Sans"'
258 font = words[0].strip('"') # TeX font name has no whitespace
259 if not font in fm.font2pkgmap:
262 fontinfo = fm.font2pkgmap[font]
263 val = fontinfo.package
264 if not val in fontmap:
266 words[0] = '"default"'
267 document.header[i] = ft + ' ' + ' '.join(words)
268 if fontinfo.scaleopt != None:
269 xval = get_value(document.header, "\\font_" + fontinfo.scaletype + "_scale", 0)
270 mo = rscales.search(xval)
275 # set correct scale option
276 fontmap[val].extend([fontinfo.scaleopt + "=" + format(float(xval1) / 100, '.2f')])
277 if len(fontinfo.options) > 0:
278 fontmap[val].extend(fontinfo.options)
281 ###############################################################################
283 ### Conversion and reversion routines
285 ###############################################################################
287 def convert_inputencoding_namechange(document):
288 " Rename inputencoding settings. "
289 i = find_token(document.header, "\\inputencoding", 0)
292 s = document.header[i].replace("auto", "auto-legacy")
293 document.header[i] = s.replace("default", "auto-legacy-plain")
295 def revert_inputencoding_namechange(document):
296 " Rename inputencoding settings. "
297 i = find_token(document.header, "\\inputencoding", 0)
300 s = document.header[i].replace("auto-legacy-plain", "default")
301 document.header[i] = s.replace("auto-legacy", "auto")
303 def convert_notoFonts(document):
304 " Handle Noto fonts definition to LaTeX "
306 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
307 fm = createFontMapping(['Noto'])
308 convert_fonts(document, fm)
310 def revert_notoFonts(document):
311 " Revert native Noto font definition to LaTeX "
313 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
315 fm = createFontMapping(['Noto'])
316 revert_fonts(document, fm, fontmap)
317 add_preamble_fonts(document, fontmap)
319 def convert_latexFonts(document):
320 " Handle DejaVu and IBMPlex fonts definition to LaTeX "
322 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
323 fm = createFontMapping(['DejaVu', 'IBM'])
324 convert_fonts(document, fm)
326 def revert_latexFonts(document):
327 " Revert native DejaVu font definition to LaTeX "
329 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
331 fm = createFontMapping(['DejaVu', 'IBM'])
332 revert_fonts(document, fm, fontmap)
333 add_preamble_fonts(document, fontmap)
335 def convert_AdobeFonts(document):
336 " Handle DejaVu and IBMPlex fonts definition to LaTeX "
338 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
339 fm = createFontMapping(['Adobe'])
340 convert_fonts(document, fm)
342 def revert_AdobeFonts(document):
343 " Revert native DejaVu font definition to LaTeX "
345 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
347 fm = createFontMapping(['Adobe'])
348 revert_fonts(document, fm, fontmap)
349 add_preamble_fonts(document, fontmap)
351 def removeFrontMatterStyles(document):
352 " Remove styles Begin/EndFrontmatter"
354 layouts = ['BeginFrontmatter', 'EndFrontmatter']
355 tokenend = len('\\begin_layout ')
358 i = find_token_exact(document.body, '\\begin_layout ', i)
361 layout = document.body[i][tokenend:].strip()
362 if layout not in layouts:
365 j = find_end_of_layout(document.body, i)
367 document.warning("Malformed LyX document: Can't find end of layout at line %d" % i)
370 while document.body[j+1].strip() == '':
372 document.body[i:j+1] = []
374 def addFrontMatterStyles(document):
375 " Use styles Begin/EndFrontmatter for elsarticle"
377 if document.textclass != "elsarticle":
380 def insertFrontmatter(prefix, line):
382 while above > 0 and document.body[above-1].strip() == '':
385 while document.body[below].strip() == '':
387 document.body[above:below] = ['', '\\begin_layout ' + prefix + 'Frontmatter',
388 '\\begin_inset Note Note',
390 '\\begin_layout Plain Layout',
393 '\\end_inset', '', '',
396 layouts = ['Title', 'Title footnote', 'Author', 'Author footnote',
397 'Corresponding author', 'Address', 'Email', 'Abstract', 'Keywords']
398 tokenend = len('\\begin_layout ')
402 i = find_token_exact(document.body, '\\begin_layout ', i)
405 layout = document.body[i][tokenend:].strip()
406 if layout not in layouts:
409 k = find_end_of_layout(document.body, i)
411 document.warning("Malformed LyX document: Can't find end of layout at line %d" % i)
419 insertFrontmatter('End', k+1)
420 insertFrontmatter('Begin', first)
423 def convert_lst_literalparam(document):
424 " Add param literal to include inset "
428 i = find_token(document.body, '\\begin_inset CommandInset include', i)
431 j = find_end_of_inset(document.body, i)
433 document.warning("Malformed LyX document: Can't find end of command inset at line %d" % i)
436 while i < j and document.body[i].strip() != '':
438 document.body.insert(i, 'literal "true"')
441 def revert_lst_literalparam(document):
442 " Remove param literal from include inset "
446 i = find_token(document.body, '\\begin_inset CommandInset include', i+1)
449 j = find_end_of_inset(document.body, i)
451 document.warning("Malformed LyX document: Can't find end of include inset at line %d" % i)
453 del_token(document.body, 'literal', i, j)
456 def revert_paratype(document):
457 " Revert ParaType font definitions to LaTeX "
459 if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
461 i1 = find_token(document.header, "\\font_roman \"PTSerif-TLF\"", 0)
462 i2 = find_token(document.header, "\\font_sans \"default\"", 0)
463 i3 = find_token(document.header, "\\font_typewriter \"default\"", 0)
464 j = find_token(document.header, "\\font_sans \"PTSans-TLF\"", 0)
465 sfval = get_value(document.header, "\\font_sf_scale", 0)
470 sfoption = "scaled=" + format(float(sfval) / 100, '.2f')
471 k = find_token(document.header, "\\font_typewriter \"PTMono-TLF\"", 0)
472 ttval = get_value(document.header, "\\font_tt_scale", 0)
477 ttoption = "scaled=" + format(float(ttval) / 100, '.2f')
478 if i1 != -1 and i2 != -1 and i3!= -1:
479 add_to_preamble(document, ["\\usepackage{paratype}"])
482 add_to_preamble(document, ["\\usepackage{PTSerif}"])
483 document.header[i1] = document.header[i1].replace("PTSerif-TLF", "default")
486 add_to_preamble(document, ["\\usepackage[" + sfoption + "]{PTSans}"])
488 add_to_preamble(document, ["\\usepackage{PTSans}"])
489 document.header[j] = document.header[j].replace("PTSans-TLF", "default")
492 add_to_preamble(document, ["\\usepackage[" + ttoption + "]{PTMono}"])
494 add_to_preamble(document, ["\\usepackage{PTMono}"])
495 document.header[k] = document.header[k].replace("PTMono-TLF", "default")
498 def revert_xcharter(document):
499 " Revert XCharter font definitions to LaTeX "
501 i = find_token(document.header, "\\font_roman \"xcharter\"", 0)
505 # replace unsupported font setting
506 document.header[i] = document.header[i].replace("xcharter", "default")
507 # no need for preamble code with system fonts
508 if get_bool_value(document.header, "\\use_non_tex_fonts"):
511 # transfer old style figures setting to package options
512 j = find_token(document.header, "\\font_osf true")
515 document.header[j] = "\\font_osf false"
519 add_to_preamble(document, ["\\usepackage%s{XCharter}"%options])
522 def revert_lscape(document):
523 " Reverts the landscape environment (Landscape module) to TeX-code "
525 if not "landscape" in document.get_module_list():
530 i = find_token(document.body, "\\begin_inset Flex Landscape", i)
533 j = find_end_of_inset(document.body, i)
535 document.warning("Malformed LyX document: Can't find end of Landscape inset")
539 if document.body[i] == "\\begin_inset Flex Landscape (Floating)":
540 document.body[j - 2 : j + 1] = put_cmd_in_ert("\\end{landscape}}")
541 document.body[i : i + 4] = put_cmd_in_ert("\\afterpage{\\begin{landscape}")
542 add_to_preamble(document, ["\\usepackage{afterpage}"])
544 document.body[j - 2 : j + 1] = put_cmd_in_ert("\\end{landscape}")
545 document.body[i : i + 4] = put_cmd_in_ert("\\begin{landscape}")
547 add_to_preamble(document, ["\\usepackage{pdflscape}"])
551 def convert_fontenc(document):
552 " Convert default fontenc setting "
554 i = find_token(document.header, "\\fontencoding global", 0)
558 document.header[i] = document.header[i].replace("global", "auto")
561 def revert_fontenc(document):
562 " Revert default fontenc setting "
564 i = find_token(document.header, "\\fontencoding auto", 0)
568 document.header[i] = document.header[i].replace("auto", "global")
571 def revert_nospellcheck(document):
572 " Remove nospellcheck font info param "
576 i = find_token(document.body, '\\nospellcheck', i)
582 def revert_floatpclass(document):
583 " Remove float placement params 'document' and 'class' "
586 i = find_token(document.header, "\\float_placement class", 0)
588 del document.header[i]
592 i = find_token(document.body, '\\begin_inset Float', i)
595 j = find_end_of_inset(document.body, i)
596 k = find_token(document.body, 'placement class', i, i + 2)
598 k = find_token(document.body, 'placement document', i, i + 2)
606 def revert_floatalignment(document):
607 " Remove float alignment params "
610 i = find_token(document.header, "\\float_alignment", 0)
613 galignment = get_value(document.header, "\\float_alignment", i)
614 del document.header[i]
618 i = find_token(document.body, '\\begin_inset Float', i)
621 j = find_end_of_inset(document.body, i)
623 document.warning("Malformed LyX document: Can't find end of inset at line " + str(i))
625 k = find_token(document.body, 'alignment', i, i + 4)
629 alignment = get_value(document.body, "alignment", k)
630 if alignment == "document":
631 alignment = galignment
633 l = find_token(document.body, "\\begin_layout Plain Layout", i, j)
635 document.warning("Can't find float layout!")
639 if alignment == "left":
640 alcmd = put_cmd_in_ert("\\raggedright{}")
641 elif alignment == "center":
642 alcmd = put_cmd_in_ert("\\centering{}")
643 elif alignment == "right":
644 alcmd = put_cmd_in_ert("\\raggedleft{}")
646 document.body[l+1:l+1] = alcmd
650 def revert_tuftecite(document):
651 " Revert \cite commands in tufte classes "
653 tufte = ["tufte-book", "tufte-handout"]
654 if document.textclass not in tufte:
659 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
662 j = find_end_of_inset(document.body, i)
664 document.warning("Can't find end of citation inset at line %d!!" %(i))
667 k = find_token(document.body, "LatexCommand", i, j)
669 document.warning("Can't find LatexCommand for citation inset at line %d!" %(i))
672 cmd = get_value(document.body, "LatexCommand", k)
676 pre = get_quoted_value(document.body, "before", i, j)
677 post = get_quoted_value(document.body, "after", i, j)
678 key = get_quoted_value(document.body, "key", i, j)
680 document.warning("Citation inset at line %d does not have a key!" %(i))
682 # Replace command with ERT
685 res += "[" + pre + "]"
687 res += "[" + post + "]"
690 res += "{" + key + "}"
691 document.body[i:j+1] = put_cmd_in_ert([res])
695 def revert_stretchcolumn(document):
696 " We remove the column varwidth flags or everything else will become a mess. "
699 i = find_token(document.body, "\\begin_inset Tabular", i)
702 j = find_end_of_inset(document.body, i + 1)
704 document.warning("Malformed LyX document: Could not find end of tabular.")
706 for k in range(i, j):
707 if re.search('^<column.*varwidth="[^"]+".*>$', document.body[k]):
708 document.warning("Converting 'tabularx'/'xltabular' table to normal table.")
709 document.body[k] = document.body[k].replace(' varwidth="true"', '')
713 def revert_vcolumns(document):
714 " Revert standard columns with line breaks etc. "
720 i = find_token(document.body, "\\begin_inset Tabular", i)
723 j = find_end_of_inset(document.body, i)
725 document.warning("Malformed LyX document: Could not find end of tabular.")
729 # Collect necessary column information
731 nrows = int(document.body[i+1].split('"')[3])
732 ncols = int(document.body[i+1].split('"')[5])
734 for k in range(ncols):
735 m = find_token(document.body, "<column", m)
736 width = get_option_value(document.body[m], 'width')
737 varwidth = get_option_value(document.body[m], 'varwidth')
738 alignment = get_option_value(document.body[m], 'alignment')
739 special = get_option_value(document.body[m], 'special')
740 col_info.append([width, varwidth, alignment, special, m])
745 for row in range(nrows):
746 for col in range(ncols):
747 m = find_token(document.body, "<cell", m)
748 multicolumn = get_option_value(document.body[m], 'multicolumn')
749 multirow = get_option_value(document.body[m], 'multirow')
750 width = get_option_value(document.body[m], 'width')
751 rotate = get_option_value(document.body[m], 'rotate')
752 # Check for: linebreaks, multipars, non-standard environments
754 endcell = find_token(document.body, "</cell>", begcell)
756 if find_token(document.body, "\\begin_inset Newline", begcell, endcell) != -1:
758 elif count_pars_in_inset(document.body, begcell + 2) > 1:
760 elif get_value(document.body, "\\begin_layout", begcell) != "Plain Layout":
762 if vcand and rotate == "" and ((multicolumn == "" and multirow == "") or width == ""):
763 if col_info[col][0] == "" and col_info[col][1] == "" and col_info[col][3] == "":
765 alignment = col_info[col][2]
766 col_line = col_info[col][4]
768 if alignment == "center":
769 vval = ">{\\centering}"
770 elif alignment == "left":
771 vval = ">{\\raggedright}"
772 elif alignment == "right":
773 vval = ">{\\raggedleft}"
776 vval += "V{\\linewidth}"
778 document.body[col_line] = document.body[col_line][:-1] + " special=\"" + vval + "\">"
779 # ERT newlines and linebreaks (since LyX < 2.4 automatically inserts parboxes
780 # with newlines, and we do not want that)
782 endcell = find_token(document.body, "</cell>", begcell)
784 nl = find_token(document.body, "\\begin_inset Newline newline", begcell, endcell)
786 nl = find_token(document.body, "\\begin_inset Newline linebreak", begcell, endcell)
790 nle = find_end_of_inset(document.body, nl)
791 del(document.body[nle:nle+1])
793 document.body[nl:nl+1] = put_cmd_in_ert("\\linebreak{}")
795 document.body[nl:nl+1] = put_cmd_in_ert("\\\\")
801 if needarray == True:
802 add_to_preamble(document, ["\\usepackage{array}"])
803 if needvarwidth == True:
804 add_to_preamble(document, ["\\usepackage{varwidth}"])
807 def revert_bibencoding(document):
808 " Revert bibliography encoding "
812 i = find_token(document.header, "\\cite_engine", 0)
814 document.warning("Malformed document! Missing \\cite_engine")
816 engine = get_value(document.header, "\\cite_engine", i)
820 if engine in ["biblatex", "biblatex-natbib"]:
823 # Map lyx to latex encoding names
827 "armscii8" : "armscii8",
828 "iso8859-1" : "latin1",
829 "iso8859-2" : "latin2",
830 "iso8859-3" : "latin3",
831 "iso8859-4" : "latin4",
832 "iso8859-5" : "iso88595",
833 "iso8859-6" : "8859-6",
834 "iso8859-7" : "iso-8859-7",
835 "iso8859-8" : "8859-8",
836 "iso8859-9" : "latin5",
837 "iso8859-13" : "latin7",
838 "iso8859-15" : "latin9",
839 "iso8859-16" : "latin10",
840 "applemac" : "applemac",
842 "cp437de" : "cp437de",
859 "utf8-platex" : "utf8",
866 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
869 j = find_end_of_inset(document.body, i)
871 document.warning("Can't find end of bibtex inset at line %d!!" %(i))
874 encoding = get_quoted_value(document.body, "encoding", i, j)
878 # remove encoding line
879 k = find_token(document.body, "encoding", i, j)
882 if encoding == "default":
885 # Re-find inset end line
886 j = find_end_of_inset(document.body, i)
889 h = find_token(document.header, "\\biblio_options", 0)
891 biblio_options = get_value(document.header, "\\biblio_options", h)
892 if not "bibencoding" in biblio_options:
893 document.header[h] += ",bibencoding=%s" % encodings[encoding]
895 bs = find_token(document.header, "\\biblatex_bibstyle", 0)
897 # this should not happen
898 document.warning("Malformed LyX document! No \\biblatex_bibstyle header found!")
900 document.header[bs-1 : bs-1] = ["\\biblio_options bibencoding=" + encodings[encoding]]
902 document.body[j+1:j+1] = put_cmd_in_ert("\\egroup")
903 document.body[i:i] = put_cmd_in_ert("\\bgroup\\inputencoding{" + encodings[encoding] + "}")
909 def convert_vcsinfo(document):
910 " Separate vcs Info inset from buffer Info inset. "
913 "vcs-revision" : "revision",
914 "vcs-tree-revision" : "tree-revision",
915 "vcs-author" : "author",
921 i = find_token(document.body, "\\begin_inset Info", i)
924 j = find_end_of_inset(document.body, i + 1)
926 document.warning("Malformed LyX document: Could not find end of Info inset.")
929 tp = find_token(document.body, 'type', i, j)
930 tpv = get_quoted_value(document.body, "type", tp)
934 arg = find_token(document.body, 'arg', i, j)
935 argv = get_quoted_value(document.body, "arg", arg)
936 if argv not in list(types.keys()):
939 document.body[tp] = "type \"vcs\""
940 document.body[arg] = "arg \"" + types[argv] + "\""
944 def revert_vcsinfo(document):
945 " Merge vcs Info inset to buffer Info inset. "
947 args = ["revision", "tree-revision", "author", "time", "date" ]
950 i = find_token(document.body, "\\begin_inset Info", i)
953 j = find_end_of_inset(document.body, i + 1)
955 document.warning("Malformed LyX document: Could not find end of Info inset.")
958 tp = find_token(document.body, 'type', i, j)
959 tpv = get_quoted_value(document.body, "type", tp)
963 arg = find_token(document.body, 'arg', i, j)
964 argv = get_quoted_value(document.body, "arg", arg)
966 document.warning("Malformed Info inset. Invalid vcs arg.")
969 document.body[tp] = "type \"buffer\""
970 document.body[arg] = "arg \"vcs-" + argv + "\""
974 def revert_dateinfo(document):
975 " Revert date info insets to static text. "
977 # FIXME This currently only considers the main language and uses the system locale
978 # Ideally, it should honor context languages and switch the locale accordingly.
980 # The date formats for each language using strftime syntax:
981 # long, short, loclong, locmedium, locshort
983 "afrikaans" : ["%A, %d %B %Y", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y/%m/%d"],
984 "albanian" : ["%A, %d %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
985 "american" : ["%A, %B %d, %Y", "%m/%d/%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
986 "amharic" : ["%A ፣%d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
987 "ancientgreek" : ["%A, %d %B %Y", "%d %b %Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
988 "arabic_arabi" : ["%A، %d %B، %Y", "%d/%m/%Y", "%d %B، %Y", "%d/%m/%Y", "%d/%m/%Y"],
989 "arabic_arabtex" : ["%A، %d %B، %Y", "%d/%m/%Y", "%d %B، %Y", "%d/%m/%Y", "%d/%m/%Y"],
990 "armenian" : ["%Y թ. %B %d, %A", "%d.%m.%y", "%d %B، %Y", "%d %b، %Y", "%d/%m/%Y"],
991 "asturian" : ["%A, %d %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d %b %Y", "%d/%m/%Y"],
992 "australian" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
993 "austrian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
994 "bahasa" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
995 "bahasam" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
996 "basque" : ["%Y(e)ko %B %d, %A", "%y/%m/%d", "%Y %B %d", "%Y %b %d", "%Y/%m/%d"],
997 "belarusian" : ["%A, %d %B %Y г.", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
998 "bosnian" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%Y-%m-%d"],
999 "brazilian" : ["%A, %d de %B de %Y", "%d/%m/%Y", "%d de %B de %Y", "%d de %b de %Y", "%d/%m/%Y"],
1000 "breton" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
1001 "british" : ["%A, %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1002 "bulgarian" : ["%A, %d %B %Y г.", "%d.%m.%y г.", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
1003 "canadian" : ["%A, %B %d, %Y", "%Y-%m-%d", "%B %d, %Y", "%d %b %Y", "%Y-%m-%d"],
1004 "canadien" : ["%A %d %B %Y", "%y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
1005 "catalan" : ["%A, %d %B de %Y", "%d/%m/%y", "%d / %B / %Y", "%d / %b / %Y", "%d/%m/%Y"],
1006 "chinese-simplified" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y-%m-%d", "%y-%m-%d"],
1007 "chinese-traditional" : ["%Y年%m月%d日 %A", "%Y/%m/%d", "%Y年%m月%d日", "%Y年%m月%d日", "%y年%m月%d日"],
1008 "coptic" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
1009 "croatian" : ["%A, %d. %B %Y.", "%d. %m. %Y.", "%d. %B %Y.", "%d. %b. %Y.", "%d.%m.%Y."],
1010 "czech" : ["%A %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b. %Y", "%d.%m.%Y"],
1011 "danish" : ["%A den %d. %B %Y", "%d/%m/%Y", "%d. %B %Y", "%d. %b %Y", "%d/%m/%Y"],
1012 "divehi" : ["%Y %B %d, %A", "%Y-%m-%d", "%Y %B %d", "%Y %b %d", "%d/%m/%Y"],
1013 "dutch" : ["%A %d %B %Y", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1014 "english" : ["%A, %B %d, %Y", "%m/%d/%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
1015 "esperanto" : ["%A, %d %B %Y", "%d %b %Y", "la %d de %B %Y", "la %d de %b %Y", "%m/%d/%Y"],
1016 "estonian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
1017 "farsi" : ["%A %d %B %Y", "%Y/%m/%d", "%d %B %Y", "%d %b %Y", "%Y/%m/%d"],
1018 "finnish" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1019 "french" : ["%A %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1020 "friulan" : ["%A %d di %B dal %Y", "%d/%m/%y", "%d di %B dal %Y", "%d di %b dal %Y", "%d/%m/%Y"],
1021 "galician" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d de %b de %Y", "%d/%m/%Y"],
1022 "georgian" : ["%A, %d %B, %Y", "%d.%m.%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
1023 "german" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1024 "german-ch" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1025 "german-ch-old" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1026 "greek" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1027 "hebrew" : ["%A, %d ב%B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1028 "hindi" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1029 "icelandic" : ["%A, %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1030 "interlingua" : ["%Y %B %d, %A", "%Y-%m-%d", "le %d de %B %Y", "le %d de %b %Y", "%Y-%m-%d"],
1031 "irish" : ["%A %d %B %Y", "%d/%m/%Y", "%d. %B %Y", "%d. %b %Y", "%d/%m/%Y"],
1032 "italian" : ["%A %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d/%b/%Y", "%d/%m/%Y"],
1033 "japanese" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y/%m/%d", "%y/%m/%d"],
1034 "japanese-cjk" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y/%m/%d", "%y/%m/%d"],
1035 "kannada" : ["%A, %B %d, %Y", "%d/%m/%y", "%d %B %Y", "%d %B %Y", "%d-%m-%Y"],
1036 "kazakh" : ["%Y ж. %d %B, %A", "%d.%m.%y", "%d %B %Y", "%d %B %Y", "%Y-%d-%m"],
1037 "khmer" : ["%A %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %B %Y", "%d/%m/%Y"],
1038 "korean" : ["%Y년 %m월 %d일 %A", "%y. %m. %d.", "%Y년 %m월 %d일", "%Y. %m. %d.", "%y. %m. %d."],
1039 "kurmanji" : ["%A, %d %B %Y", "%d %b %Y", "%d. %B %Y", "%d. %m. %Y", "%Y-%m-%d"],
1040 "lao" : ["%A ທີ %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %B %Y", "%d/%m/%Y"],
1041 "latin" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
1042 "latvian" : ["%A, %Y. gada %d. %B", "%d.%m.%y", "%Y. gada %d. %B", "%Y. gada %d. %b", "%d.%m.%Y"],
1043 "lithuanian" : ["%Y m. %B %d d., %A", "%Y-%m-%d", "%Y m. %B %d d.", "%Y m. %B %d d.", "%Y-%m-%d"],
1044 "lowersorbian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
1045 "macedonian" : ["%A, %d %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
1046 "magyar" : ["%Y. %B %d., %A", "%Y. %m. %d.", "%Y. %B %d.", "%Y. %b %d.", "%Y.%m.%d."],
1047 "malayalam" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1048 "marathi" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1049 "mongolian" : ["%A, %Y оны %m сарын %d", "%Y-%m-%d", "%Y оны %m сарын %d", "%d-%m-%Y", "%d-%m-%Y"],
1050 "naustrian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1051 "newzealand" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1052 "ngerman" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1053 "norsk" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1054 "nynorsk" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1055 "occitan" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1056 "piedmontese" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
1057 "polish" : ["%A, %d %B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
1058 "polutonikogreek" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1059 "portuguese" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d de %b de %Y", "%Y/%m/%d"],
1060 "romanian" : ["%A, %d %B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
1061 "romansh" : ["%A, ils %d da %B %Y", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
1062 "russian" : ["%A, %d %B %Y г.", "%d.%m.%Y", "%d %B %Y г.", "%d %b %Y г.", "%d.%m.%Y"],
1063 "samin" : ["%Y %B %d, %A", "%Y-%m-%d", "%B %d. b. %Y", "%b %d. b. %Y", "%d.%m.%Y"],
1064 "sanskrit" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1065 "scottish" : ["%A, %dmh %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1066 "serbian" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1067 "serbian-latin" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1068 "slovak" : ["%A, %d. %B %Y", "%d. %m. %Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1069 "slovene" : ["%A, %d. %B %Y", "%d. %m. %y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
1070 "spanish" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B %de %Y", "%d %b %Y", "%d/%m/%Y"],
1071 "spanish-mexico" : ["%A, %d de %B %de %Y", "%d/%m/%y", "%d de %B de %Y", "%d %b %Y", "%d/%m/%Y"],
1072 "swedish" : ["%A %d %B %Y", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
1073 "syriac" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1074 "tamil" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1075 "telugu" : ["%d, %B %Y, %A", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
1076 "thai" : ["%Aที่ %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1077 "tibetan" : ["%Y %Bའི་ཚེས་%d, %A", "%Y-%m-%d", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
1078 "turkish" : ["%d %B %Y %A", "%d.%m.%Y", "%d %B %Y", "%d.%b.%Y", "%d.%m.%Y"],
1079 "turkmen" : ["%d %B %Y %A", "%d.%m.%Y", "%Y ý. %B %d", "%d.%m.%Y ý.", "%d.%m.%y ý."],
1080 "ukrainian" : ["%A, %d %B %Y р.", "%d.%m.%y", "%d %B %Y", "%d %m %Y", "%d.%m.%Y"],
1081 "uppersorbian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
1082 "urdu" : ["%A، %d %B، %Y", "%d/%m/%y", "%d %B, %Y", "%d %b %Y", "%d/%m/%Y"],
1083 "vietnamese" : ["%A, %d %B, %Y", "%d/%m/%Y", "%d tháng %B %Y", "%d-%m-%Y", "%d/%m/%Y"],
1084 "welsh" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
1087 types = ["date", "fixdate", "moddate" ]
1088 lang = get_value(document.header, "\\language")
1090 document.warning("Malformed LyX document! No \\language header found!")
1095 i = find_token(document.body, "\\begin_inset Info", i)
1098 j = find_end_of_inset(document.body, i + 1)
1100 document.warning("Malformed LyX document: Could not find end of Info inset.")
1103 tp = find_token(document.body, 'type', i, j)
1104 tpv = get_quoted_value(document.body, "type", tp)
1105 if tpv not in types:
1108 arg = find_token(document.body, 'arg', i, j)
1109 argv = get_quoted_value(document.body, "arg", arg)
1112 if tpv == "fixdate":
1113 datecomps = argv.split('@')
1114 if len(datecomps) > 1:
1116 isodate = datecomps[1]
1117 m = re.search('(\d\d\d\d)-(\d\d)-(\d\d)', isodate)
1119 dte = date(int(m.group(1)), int(m.group(2)), int(m.group(3)))
1120 # FIXME if we had the path to the original document (not the one in the tmp dir),
1121 # we could use the mtime.
1122 # elif tpv == "moddate":
1123 # dte = date.fromtimestamp(os.path.getmtime(document.dir))
1126 result = dte.isodate()
1127 elif argv == "long":
1128 result = dte.strftime(dateformats[lang][0])
1129 elif argv == "short":
1130 result = dte.strftime(dateformats[lang][1])
1131 elif argv == "loclong":
1132 result = dte.strftime(dateformats[lang][2])
1133 elif argv == "locmedium":
1134 result = dte.strftime(dateformats[lang][3])
1135 elif argv == "locshort":
1136 result = dte.strftime(dateformats[lang][4])
1138 fmt = argv.replace("MMMM", "%b").replace("MMM", "%b").replace("MM", "%m").replace("M", "%m")
1139 fmt = fmt.replace("yyyy", "%Y").replace("yy", "%y")
1140 fmt = fmt.replace("dddd", "%A").replace("ddd", "%a").replace("dd", "%d")
1141 fmt = re.sub('[^\'%]d', '%d', fmt)
1142 fmt = fmt.replace("'", "")
1143 result = dte.strftime(fmt)
1144 if sys.version_info < (3,0):
1145 # In Python 2, datetime module works with binary strings,
1146 # our dateformat strings are utf8-encoded:
1147 result = result.decode('utf-8')
1148 document.body[i : j+1] = [result]
1152 def revert_timeinfo(document):
1153 " Revert time info insets to static text. "
1155 # FIXME This currently only considers the main language and uses the system locale
1156 # Ideally, it should honor context languages and switch the locale accordingly.
1157 # Also, the time object is "naive", i.e., it does not know of timezones (%Z will
1160 # The time formats for each language using strftime syntax:
1163 "afrikaans" : ["%H:%M:%S %Z", "%H:%M"],
1164 "albanian" : ["%I:%M:%S %p, %Z", "%I:%M %p"],
1165 "american" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1166 "amharic" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1167 "ancientgreek" : ["%H:%M:%S %Z", "%H:%M:%S"],
1168 "arabic_arabi" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1169 "arabic_arabtex" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1170 "armenian" : ["%H:%M:%S %Z", "%H:%M"],
1171 "asturian" : ["%H:%M:%S %Z", "%H:%M"],
1172 "australian" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1173 "austrian" : ["%H:%M:%S %Z", "%H:%M"],
1174 "bahasa" : ["%H.%M.%S %Z", "%H.%M"],
1175 "bahasam" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1176 "basque" : ["%H:%M:%S (%Z)", "%H:%M"],
1177 "belarusian" : ["%H:%M:%S, %Z", "%H:%M"],
1178 "bosnian" : ["%H:%M:%S %Z", "%H:%M"],
1179 "brazilian" : ["%H:%M:%S %Z", "%H:%M"],
1180 "breton" : ["%H:%M:%S %Z", "%H:%M"],
1181 "british" : ["%H:%M:%S %Z", "%H:%M"],
1182 "bulgarian" : ["%H:%M:%S %Z", "%H:%M"],
1183 "canadian" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1184 "canadien" : ["%H:%M:%S %Z", "%H h %M"],
1185 "catalan" : ["%H:%M:%S %Z", "%H:%M"],
1186 "chinese-simplified" : ["%Z %p%I:%M:%S", "%p%I:%M"],
1187 "chinese-traditional" : ["%p%I:%M:%S [%Z]", "%p%I:%M"],
1188 "coptic" : ["%H:%M:%S %Z", "%H:%M:%S"],
1189 "croatian" : ["%H:%M:%S (%Z)", "%H:%M"],
1190 "czech" : ["%H:%M:%S %Z", "%H:%M"],
1191 "danish" : ["%H.%M.%S %Z", "%H.%M"],
1192 "divehi" : ["%H:%M:%S %Z", "%H:%M"],
1193 "dutch" : ["%H:%M:%S %Z", "%H:%M"],
1194 "english" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1195 "esperanto" : ["%H:%M:%S %Z", "%H:%M:%S"],
1196 "estonian" : ["%H:%M:%S %Z", "%H:%M"],
1197 "farsi" : ["%H:%M:%S (%Z)", "%H:%M"],
1198 "finnish" : ["%H.%M.%S %Z", "%H.%M"],
1199 "french" : ["%H:%M:%S %Z", "%H:%M"],
1200 "friulan" : ["%H:%M:%S %Z", "%H:%M"],
1201 "galician" : ["%H:%M:%S %Z", "%H:%M"],
1202 "georgian" : ["%H:%M:%S %Z", "%H:%M"],
1203 "german" : ["%H:%M:%S %Z", "%H:%M"],
1204 "german-ch" : ["%H:%M:%S %Z", "%H:%M"],
1205 "german-ch-old" : ["%H:%M:%S %Z", "%H:%M"],
1206 "greek" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1207 "hebrew" : ["%H:%M:%S %Z", "%H:%M"],
1208 "hindi" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1209 "icelandic" : ["%H:%M:%S %Z", "%H:%M"],
1210 "interlingua" : ["%H:%M:%S %Z", "%H:%M"],
1211 "irish" : ["%H:%M:%S %Z", "%H:%M"],
1212 "italian" : ["%H:%M:%S %Z", "%H:%M"],
1213 "japanese" : ["%H時%M分%S秒 %Z", "%H:%M"],
1214 "japanese-cjk" : ["%H時%M分%S秒 %Z", "%H:%M"],
1215 "kannada" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1216 "kazakh" : ["%H:%M:%S %Z", "%H:%M"],
1217 "khmer" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1218 "korean" : ["%p %I시%M분 %S초 %Z", "%p %I:%M"],
1219 "kurmanji" : ["%H:%M:%S %Z", "%H:%M:%S"],
1220 "lao" : ["%H ໂມງ%M ນາທີ %S ວິນາທີ %Z", "%H:%M"],
1221 "latin" : ["%H:%M:%S %Z", "%H:%M:%S"],
1222 "latvian" : ["%H:%M:%S %Z", "%H:%M"],
1223 "lithuanian" : ["%H:%M:%S %Z", "%H:%M"],
1224 "lowersorbian" : ["%H:%M:%S %Z", "%H:%M"],
1225 "macedonian" : ["%H:%M:%S %Z", "%H:%M"],
1226 "magyar" : ["%H:%M:%S %Z", "%H:%M"],
1227 "malayalam" : ["%p %I:%M:%S %Z", "%p %I:%M"],
1228 "marathi" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1229 "mongolian" : ["%H:%M:%S %Z", "%H:%M"],
1230 "naustrian" : ["%H:%M:%S %Z", "%H:%M"],
1231 "newzealand" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1232 "ngerman" : ["%H:%M:%S %Z", "%H:%M"],
1233 "norsk" : ["%H:%M:%S %Z", "%H:%M"],
1234 "nynorsk" : ["kl. %H:%M:%S %Z", "%H:%M"],
1235 "occitan" : ["%H:%M:%S %Z", "%H:%M"],
1236 "piedmontese" : ["%H:%M:%S %Z", "%H:%M:%S"],
1237 "polish" : ["%H:%M:%S %Z", "%H:%M"],
1238 "polutonikogreek" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1239 "portuguese" : ["%H:%M:%S %Z", "%H:%M"],
1240 "romanian" : ["%H:%M:%S %Z", "%H:%M"],
1241 "romansh" : ["%H:%M:%S %Z", "%H:%M"],
1242 "russian" : ["%H:%M:%S %Z", "%H:%M"],
1243 "samin" : ["%H:%M:%S %Z", "%H:%M"],
1244 "sanskrit" : ["%H:%M:%S %Z", "%H:%M"],
1245 "scottish" : ["%H:%M:%S %Z", "%H:%M"],
1246 "serbian" : ["%H:%M:%S %Z", "%H:%M"],
1247 "serbian-latin" : ["%H:%M:%S %Z", "%H:%M"],
1248 "slovak" : ["%H:%M:%S %Z", "%H:%M"],
1249 "slovene" : ["%H:%M:%S %Z", "%H:%M"],
1250 "spanish" : ["%H:%M:%S (%Z)", "%H:%M"],
1251 "spanish-mexico" : ["%H:%M:%S %Z", "%H:%M"],
1252 "swedish" : ["kl. %H:%M:%S %Z", "%H:%M"],
1253 "syriac" : ["%H:%M:%S %Z", "%H:%M"],
1254 "tamil" : ["%p %I:%M:%S %Z", "%p %I:%M"],
1255 "telugu" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1256 "thai" : ["%H นาฬิกา %M นาที %S วินาที %Z", "%H:%M"],
1257 "tibetan" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1258 "turkish" : ["%H:%M:%S %Z", "%H:%M"],
1259 "turkmen" : ["%H:%M:%S %Z", "%H:%M"],
1260 "ukrainian" : ["%H:%M:%S %Z", "%H:%M"],
1261 "uppersorbian" : ["%H:%M:%S %Z", "%H:%M hodź."],
1262 "urdu" : ["%I:%M:%S %p %Z", "%I:%M %p"],
1263 "vietnamese" : ["%H:%M:%S %Z", "%H:%M"],
1264 "welsh" : ["%H:%M:%S %Z", "%H:%M"]
1267 types = ["time", "fixtime", "modtime" ]
1269 i = find_token(document.header, "\\language", 0)
1271 # this should not happen
1272 document.warning("Malformed LyX document! No \\language header found!")
1274 lang = get_value(document.header, "\\language", i)
1278 i = find_token(document.body, "\\begin_inset Info", i)
1281 j = find_end_of_inset(document.body, i + 1)
1283 document.warning("Malformed LyX document: Could not find end of Info inset.")
1286 tp = find_token(document.body, 'type', i, j)
1287 tpv = get_quoted_value(document.body, "type", tp)
1288 if tpv not in types:
1291 arg = find_token(document.body, 'arg', i, j)
1292 argv = get_quoted_value(document.body, "arg", arg)
1294 dtme = datetime.now()
1296 if tpv == "fixtime":
1297 timecomps = argv.split('@')
1298 if len(timecomps) > 1:
1300 isotime = timecomps[1]
1301 m = re.search('(\d\d):(\d\d):(\d\d)', isotime)
1303 tme = time(int(m.group(1)), int(m.group(2)), int(m.group(3)))
1305 m = re.search('(\d\d):(\d\d)', isotime)
1307 tme = time(int(m.group(1)), int(m.group(2)))
1308 # FIXME if we had the path to the original document (not the one in the tmp dir),
1309 # we could use the mtime.
1310 # elif tpv == "moddate":
1311 # dte = date.fromtimestamp(os.path.getmtime(document.dir))
1314 result = tme.isoformat()
1315 elif argv == "long":
1316 result = tme.strftime(timeformats[lang][0])
1317 elif argv == "short":
1318 result = tme.strftime(timeformats[lang][1])
1320 fmt = argv.replace("HH", "%H").replace("H", "%H").replace("hh", "%I").replace("h", "%I")
1321 fmt = fmt.replace("mm", "%M").replace("m", "%M").replace("ss", "%S").replace("s", "%S")
1322 fmt = fmt.replace("zzz", "%f").replace("z", "%f").replace("t", "%Z")
1323 fmt = fmt.replace("AP", "%p").replace("ap", "%p").replace("A", "%p").replace("a", "%p")
1324 fmt = fmt.replace("'", "")
1325 result = dte.strftime(fmt)
1326 document.body[i : j+1] = result
1330 def revert_namenoextinfo(document):
1331 " Merge buffer Info inset type name-noext to name. "
1335 i = find_token(document.body, "\\begin_inset Info", i)
1338 j = find_end_of_inset(document.body, i + 1)
1340 document.warning("Malformed LyX document: Could not find end of Info inset.")
1343 tp = find_token(document.body, 'type', i, j)
1344 tpv = get_quoted_value(document.body, "type", tp)
1348 arg = find_token(document.body, 'arg', i, j)
1349 argv = get_quoted_value(document.body, "arg", arg)
1350 if argv != "name-noext":
1353 document.body[arg] = "arg \"name\""
1357 def revert_l7ninfo(document):
1358 " Revert l7n Info inset to text. "
1362 i = find_token(document.body, "\\begin_inset Info", i)
1365 j = find_end_of_inset(document.body, i + 1)
1367 document.warning("Malformed LyX document: Could not find end of Info inset.")
1370 tp = find_token(document.body, 'type', i, j)
1371 tpv = get_quoted_value(document.body, "type", tp)
1375 arg = find_token(document.body, 'arg', i, j)
1376 argv = get_quoted_value(document.body, "arg", arg)
1377 # remove trailing colons, menu accelerator (|...) and qt accelerator (&), while keeping literal " & "
1378 argv = argv.rstrip(':').split('|')[0].replace(" & ", "</amp;>").replace("&", "").replace("</amp;>", " & ")
1379 document.body[i : j+1] = argv
1383 def revert_listpargs(document):
1384 " Reverts listpreamble arguments to TeX-code "
1387 i = find_token(document.body, "\\begin_inset Argument listpreamble:", i)
1390 j = find_end_of_inset(document.body, i)
1391 # Find containing paragraph layout
1392 parent = get_containing_layout(document.body, i)
1394 document.warning("Malformed LyX document: Can't find parent paragraph layout")
1398 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
1399 endPlain = find_end_of_layout(document.body, beginPlain)
1400 content = document.body[beginPlain + 1 : endPlain]
1401 del document.body[i:j+1]
1402 subst = ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Plain Layout",
1403 "{"] + content + ["}", "\\end_layout", "", "\\end_inset", ""]
1404 document.body[parbeg : parbeg] = subst
1408 def revert_lformatinfo(document):
1409 " Revert layout format Info inset to text. "
1413 i = find_token(document.body, "\\begin_inset Info", i)
1416 j = find_end_of_inset(document.body, i + 1)
1418 document.warning("Malformed LyX document: Could not find end of Info inset.")
1421 tp = find_token(document.body, 'type', i, j)
1422 tpv = get_quoted_value(document.body, "type", tp)
1423 if tpv != "lyxinfo":
1426 arg = find_token(document.body, 'arg', i, j)
1427 argv = get_quoted_value(document.body, "arg", arg)
1428 if argv != "layoutformat":
1432 document.body[i : j+1] = "69"
1436 def convert_hebrew_parentheses(document):
1437 """ Swap opening/closing parentheses in Hebrew text.
1439 Up to LyX 2.4, "(" was used as closing parenthesis and
1440 ")" as opening parenthesis for Hebrew in the LyX source.
1442 # print("convert hebrew parentheses")
1443 current_languages = [document.language]
1444 for i, line in enumerate(document.body):
1445 if line.startswith('\\lang '):
1446 current_languages[-1] = line.lstrip('\\lang ')
1447 elif line.startswith('\\begin_layout'):
1448 current_languages.append(current_languages[-1])
1449 # print (line, current_languages[-1])
1450 elif line.startswith('\\end_layout'):
1451 current_languages.pop()
1452 elif current_languages[-1] == 'hebrew' and not line.startswith('\\'):
1453 document.body[i] = line.replace('(','\x00').replace(')','(').replace('\x00',')')
1456 def revert_hebrew_parentheses(document):
1457 " Store parentheses in Hebrew text reversed"
1458 # This only exists to keep the convert/revert naming convention
1459 convert_hebrew_parentheses(document)
1462 def revert_malayalam(document):
1463 " Set the document language to English but assure Malayalam output "
1465 revert_language(document, "malayalam", "", "malayalam")
1468 def revert_soul(document):
1469 " Revert soul module flex insets to ERT "
1471 flexes = ["Spaceletters", "Strikethrough", "Underline", "Highlight", "Capitalize"]
1474 i = find_token(document.body, "\\begin_inset Flex %s" % flex, 0)
1476 add_to_preamble(document, ["\\usepackage{soul}"])
1478 i = find_token(document.body, "\\begin_inset Flex Highlight", 0)
1480 add_to_preamble(document, ["\\usepackage{color}"])
1482 revert_flex_inset(document.body, "Spaceletters", "\\so")
1483 revert_flex_inset(document.body, "Strikethrough", "\\st")
1484 revert_flex_inset(document.body, "Underline", "\\ul")
1485 revert_flex_inset(document.body, "Highlight", "\\hl")
1486 revert_flex_inset(document.body, "Capitalize", "\\caps")
1489 def revert_tablestyle(document):
1490 " Remove tablestyle params "
1493 i = find_token(document.header, "\\tablestyle", 0)
1495 del document.header[i]
1498 def revert_bibfileencodings(document):
1499 " Revert individual Biblatex bibliography encodings "
1503 i = find_token(document.header, "\\cite_engine", 0)
1505 document.warning("Malformed document! Missing \\cite_engine")
1507 engine = get_value(document.header, "\\cite_engine", i)
1511 if engine in ["biblatex", "biblatex-natbib"]:
1514 # Map lyx to latex encoding names
1518 "armscii8" : "armscii8",
1519 "iso8859-1" : "latin1",
1520 "iso8859-2" : "latin2",
1521 "iso8859-3" : "latin3",
1522 "iso8859-4" : "latin4",
1523 "iso8859-5" : "iso88595",
1524 "iso8859-6" : "8859-6",
1525 "iso8859-7" : "iso-8859-7",
1526 "iso8859-8" : "8859-8",
1527 "iso8859-9" : "latin5",
1528 "iso8859-13" : "latin7",
1529 "iso8859-15" : "latin9",
1530 "iso8859-16" : "latin10",
1531 "applemac" : "applemac",
1533 "cp437de" : "cp437de",
1541 "cp1250" : "cp1250",
1542 "cp1251" : "cp1251",
1543 "cp1252" : "cp1252",
1544 "cp1255" : "cp1255",
1545 "cp1256" : "cp1256",
1546 "cp1257" : "cp1257",
1547 "koi8-r" : "koi8-r",
1548 "koi8-u" : "koi8-u",
1550 "utf8-platex" : "utf8",
1557 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1560 j = find_end_of_inset(document.body, i)
1562 document.warning("Can't find end of bibtex inset at line %d!!" %(i))
1565 encodings = get_quoted_value(document.body, "file_encodings", i, j)
1569 bibfiles = get_quoted_value(document.body, "bibfiles", i, j).split(",")
1570 opts = get_quoted_value(document.body, "biblatexopts", i, j)
1571 if len(bibfiles) == 0:
1572 document.warning("Bibtex inset at line %d does not have a bibfile!" %(i))
1573 # remove encoding line
1574 k = find_token(document.body, "file_encodings", i, j)
1576 del document.body[k]
1577 # Re-find inset end line
1578 j = find_end_of_inset(document.body, i)
1580 enclist = encodings.split("\t")
1583 ppp = pp.split(" ", 1)
1584 encmap[ppp[0]] = ppp[1]
1585 for bib in bibfiles:
1586 pr = "\\addbibresource"
1587 if bib in encmap.keys():
1588 pr += "[bibencoding=" + encmap[bib] + "]"
1589 pr += "{" + bib + "}"
1590 add_to_preamble(document, [pr])
1591 # Insert ERT \\printbibliography and wrap bibtex inset to a Note
1592 pcmd = "printbibliography"
1594 pcmd += "[" + opts + "]"
1595 repl = ["\\begin_inset ERT", "status open", "", "\\begin_layout Plain Layout",\
1596 "", "", "\\backslash", pcmd, "\\end_layout", "", "\\end_inset", "", "",\
1597 "\\end_layout", "", "\\begin_layout Standard", "\\begin_inset Note Note",\
1598 "status open", "", "\\begin_layout Plain Layout" ]
1599 repl += document.body[i:j+1]
1600 repl += ["", "\\end_layout", "", "\\end_inset", "", ""]
1601 document.body[i:j+1] = repl
1607 def revert_cmidruletrimming(document):
1608 " Remove \\cmidrule trimming "
1610 # FIXME: Revert to TeX code?
1613 # first, let's find out if we need to do anything
1614 i = find_token(document.body, '<cell ', i)
1617 j = document.body[i].find('trim="')
1621 rgx = re.compile(r' (bottom|top)line[lr]trim="true"')
1622 # remove trim option
1623 document.body[i] = rgx.sub('', document.body[i])
1629 r'### Inserted by lyx2lyx (ruby inset) ###',
1630 r'InsetLayout Flex:Ruby',
1631 r' LyxType charstyle',
1632 r' LatexType command',
1636 r' HTMLInnerTag rb',
1637 r' HTMLInnerAttr ""',
1639 r' LabelString "Ruby"',
1640 r' Decoration Conglomerate',
1642 r' \ifdefined\kanjiskip',
1643 r' \IfFileExists{okumacro.sty}{\usepackage{okumacro}}{}',
1644 r' \else \ifdefined\luatexversion',
1645 r' \usepackage{luatexja-ruby}',
1646 r' \else \ifdefined\XeTeXversion',
1647 r' \usepackage{ruby}%',
1649 r' \providecommand{\ruby}[2]{\shortstack{\tiny #2\\#1}}',
1651 r' Argument post:1',
1652 r' LabelString "ruby text"',
1653 r' MenuString "Ruby Text|R"',
1654 r' Tooltip "Reading aid (ruby, furigana) for Chinese characters."',
1655 r' Decoration Conglomerate',
1667 def convert_ruby_module(document):
1668 " Use ruby module instead of local module definition "
1669 if document.del_local_layout(ruby_inset_def):
1670 document.add_module("ruby")
1672 def revert_ruby_module(document):
1673 " Replace ruby module with local module definition "
1674 if document.del_module("ruby"):
1675 document.append_local_layout(ruby_inset_def)
1678 def convert_utf8_japanese(document):
1679 " Use generic utf8 with Japanese documents."
1680 lang = get_value(document.header, "\\language")
1681 if not lang.startswith("japanese"):
1683 inputenc = get_value(document.header, "\\inputencoding")
1684 if ((lang == "japanese" and inputenc == "utf8-platex")
1685 or (lang == "japanese-cjk" and inputenc == "utf8-cjk")):
1686 document.set_parameter("inputencoding", "utf8")
1688 def revert_utf8_japanese(document):
1689 " Use Japanese utf8 variants with Japanese documents."
1690 inputenc = get_value(document.header, "\\inputencoding")
1691 if inputenc != "utf8":
1693 lang = get_value(document.header, "\\language")
1694 if lang == "japanese":
1695 document.set_parameter("inputencoding", "utf8-platex")
1696 if lang == "japanese-cjk":
1697 document.set_parameter("inputencoding", "utf8-cjk")
1700 def revert_lineno(document):
1701 " Replace lineno setting with user-preamble code."
1703 options = get_quoted_value(document.header, "\\lineno_options",
1705 if not get_bool_value(document.header, "\\use_lineno", delete=True):
1708 options = "[" + options + "]"
1709 add_to_preamble(document, ["\\usepackage%s{lineno}" % options,
1712 def convert_lineno(document):
1713 " Replace user-preamble code with native lineno support."
1716 j = find_token(document.preamble, "\\linenumbers", 1)
1718 usepkg = re.match(r"\\usepackage(.*){lineno}", document.preamble[j-1])
1721 options = usepkg.group(1).strip("[]")
1722 del(document.preamble[j-1:j+1])
1723 del_token(document.preamble, "% Added by lyx2lyx", j-2, j-1)
1725 k = find_token(document.header, "\\index ")
1727 document.header[k:k] = ["\\use_lineno %d" % use_lineno]
1729 document.header[k:k] = ["\\use_lineno %d" % use_lineno,
1730 "\\lineno_options %s" % options]
1733 def revert_new_languages(document):
1734 """Emulate support for Azerbaijani, Bengali, Church Slavonic, Korean,
1735 and Russian (Petrine orthography)."""
1737 # lyxname: (babelname, polyglossianame)
1738 new_languages = {"azerbaijani": ("azerbaijani", ""),
1739 "bengali": ("", "bengali"),
1740 "churchslavonic": ("", "churchslavonic"),
1741 "oldrussian": ("", "russian"),
1742 "korean": ("", "korean"),
1744 used_languages = set()
1745 if document.language in new_languages:
1746 used_languages.add(document.language)
1749 i = find_token(document.body, "\\lang", i+1)
1752 if document.body[i][6:].strip() in new_languages:
1753 used_languages.add(document.language)
1755 # Korean is already supported via CJK, so leave as-is for Babel
1756 if ("korean" in used_languages
1757 and get_bool_value(document.header, "\\use_non_tex_fonts")
1758 and get_value(document.header, "\\language_package") in ("default", "auto")):
1759 revert_language(document, "korean", "", "korean")
1760 used_languages.discard("korean")
1762 for lang in used_languages:
1763 revert(lang, *new_languages[lang])
1767 r'### Inserted by lyx2lyx (deprecated ling glosses) ###',
1768 r'InsetLayout Flex:Glosse',
1770 r' LabelString "Gloss (old version)"',
1771 r' MenuString "Gloss (old version)"',
1772 r' LatexType environment',
1773 r' LatexName linggloss',
1774 r' Decoration minimalistic',
1779 r' CustomPars false',
1780 r' ForcePlain true',
1781 r' ParbreakIsNewline true',
1782 r' FreeSpacing true',
1783 r' Requires covington',
1786 r' \@ifundefined{linggloss}{%',
1787 r' \newenvironment{linggloss}[2][]{',
1788 r' \def\glosstr{\glt #1}%',
1790 r' {\glosstr\glend}}{}',
1793 r' ResetsFont true',
1795 r' Decoration conglomerate',
1796 r' LabelString "Translation"',
1797 r' MenuString "Glosse Translation|s"',
1798 r' Tooltip "Add a translation for the glosse"',
1803 glosss_inset_def = [
1804 r'### Inserted by lyx2lyx (deprecated ling glosses) ###',
1805 r'InsetLayout Flex:Tri-Glosse',
1807 r' LabelString "Tri-Gloss (old version)"',
1808 r' MenuString "Tri-Gloss (old version)"',
1809 r' LatexType environment',
1810 r' LatexName lingglosss',
1811 r' Decoration minimalistic',
1816 r' CustomPars false',
1817 r' ForcePlain true',
1818 r' ParbreakIsNewline true',
1819 r' FreeSpacing true',
1821 r' Requires covington',
1824 r' \@ifundefined{lingglosss}{%',
1825 r' \newenvironment{lingglosss}[2][]{',
1826 r' \def\glosstr{\glt #1}%',
1828 r' {\glosstr\glend}}{}',
1830 r' ResetsFont true',
1832 r' Decoration conglomerate',
1833 r' LabelString "Translation"',
1834 r' MenuString "Glosse Translation|s"',
1835 r' Tooltip "Add a translation for the glosse"',
1840 def convert_linggloss(document):
1841 " Move old ling glosses to local layout "
1842 if find_token(document.body, '\\begin_inset Flex Glosse', 0) != -1:
1843 document.append_local_layout(gloss_inset_def)
1844 if find_token(document.body, '\\begin_inset Flex Tri-Glosse', 0) != -1:
1845 document.append_local_layout(glosss_inset_def)
1847 def revert_linggloss(document):
1848 " Revert to old ling gloss definitions "
1849 document.del_local_layout(gloss_inset_def)
1850 document.del_local_layout(glosss_inset_def)
1852 if not "linguistics" in document.get_module_list():
1856 glosses = ["\\begin_inset Flex Interlinear Gloss (2 Lines)", "\\begin_inset Flex Interlinear Gloss (3 Lines)"]
1857 for glosse in glosses:
1860 i = find_token(document.body, glosse, i)
1863 j = find_end_of_inset(document.body, i)
1865 document.warning("Malformed LyX document: Can't find end of Gloss inset")
1869 arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
1870 endarg = find_end_of_inset(document.body, arg)
1873 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
1874 if argbeginPlain == -1:
1875 document.warning("Malformed LyX document: Can't find optarg plain Layout")
1878 argendPlain = find_end_of_inset(document.body, argbeginPlain)
1879 optargcontent = document.body[argbeginPlain + 1 : argendPlain - 2]
1881 # remove Arg insets and paragraph, if it only contains this inset
1882 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
1883 del document.body[arg - 1 : endarg + 4]
1885 del document.body[arg : endarg + 1]
1887 arg = find_token(document.body, "\\begin_inset Argument post:1", i, j)
1888 endarg = find_end_of_inset(document.body, arg)
1891 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
1892 if argbeginPlain == -1:
1893 document.warning("Malformed LyX document: Can't find arg 1 plain Layout")
1896 argendPlain = find_end_of_inset(document.body, argbeginPlain)
1897 marg1content = document.body[argbeginPlain + 1 : argendPlain - 2]
1899 # remove Arg insets and paragraph, if it only contains this inset
1900 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
1901 del document.body[arg - 1 : endarg + 4]
1903 del document.body[arg : endarg + 1]
1905 arg = find_token(document.body, "\\begin_inset Argument post:2", i, j)
1906 endarg = find_end_of_inset(document.body, arg)
1909 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
1910 if argbeginPlain == -1:
1911 document.warning("Malformed LyX document: Can't find arg 2 plain Layout")
1914 argendPlain = find_end_of_inset(document.body, argbeginPlain)
1915 marg2content = document.body[argbeginPlain + 1 : argendPlain - 2]
1917 # remove Arg insets and paragraph, if it only contains this inset
1918 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
1919 del document.body[arg - 1 : endarg + 4]
1921 del document.body[arg : endarg + 1]
1923 arg = find_token(document.body, "\\begin_inset Argument post:3", i, j)
1924 endarg = find_end_of_inset(document.body, arg)
1927 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
1928 if argbeginPlain == -1:
1929 document.warning("Malformed LyX document: Can't find arg 3 plain Layout")
1932 argendPlain = find_end_of_inset(document.body, argbeginPlain)
1933 marg3content = document.body[argbeginPlain + 1 : argendPlain - 2]
1935 # remove Arg insets and paragraph, if it only contains this inset
1936 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
1937 del document.body[arg - 1 : endarg + 4]
1939 del document.body[arg : endarg + 1]
1942 if glosse == "\\begin_inset Flex Interlinear Gloss (3 Lines)":
1945 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
1946 endInset = find_end_of_inset(document.body, i)
1947 endPlain = find_token_backwards(document.body, "\\end_layout", endInset)
1948 precontent = put_cmd_in_ert(cmd)
1949 if len(optargcontent) > 0:
1950 precontent += put_cmd_in_ert("[") + optargcontent + put_cmd_in_ert("]")
1951 precontent += put_cmd_in_ert("{")
1953 postcontent = put_cmd_in_ert("}{") + marg1content + put_cmd_in_ert("}{") + marg2content
1954 if cmd == "\\trigloss":
1955 postcontent += put_cmd_in_ert("}{") + marg3content
1956 postcontent += put_cmd_in_ert("}")
1958 document.body[endPlain:endInset + 1] = postcontent
1959 document.body[beginPlain + 1:beginPlain] = precontent
1960 del document.body[i : beginPlain + 1]
1962 document.append_local_layout("Requires covington")
1967 def revert_subexarg(document):
1968 " Revert linguistic subexamples with argument to ERT "
1970 if not "linguistics" in document.get_module_list():
1976 i = find_token(document.body, "\\begin_layout Subexample", i)
1979 j = find_end_of_layout(document.body, i)
1981 document.warning("Malformed LyX document: Can't find end of Subexample layout")
1985 # check for consecutive layouts
1986 k = find_token(document.body, "\\begin_layout", j)
1987 if k == -1 or document.body[k] != "\\begin_layout Subexample":
1989 j = find_end_of_layout(document.body, k)
1991 document.warning("Malformed LyX document: Can't find end of Subexample layout")
1995 arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
2000 endarg = find_end_of_inset(document.body, arg)
2002 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
2003 if argbeginPlain == -1:
2004 document.warning("Malformed LyX document: Can't find optarg plain Layout")
2007 argendPlain = find_end_of_inset(document.body, argbeginPlain)
2008 optargcontent = lyx2latex(document, document.body[argbeginPlain + 1 : argendPlain - 2])
2010 # remove Arg insets and paragraph, if it only contains this inset
2011 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
2012 del document.body[arg - 1 : endarg + 4]
2014 del document.body[arg : endarg + 1]
2016 cmd = put_cmd_in_ert("\\begin{subexamples}[" + optargcontent + "]")
2018 # re-find end of layout
2019 j = find_end_of_layout(document.body, i)
2021 document.warning("Malformed LyX document: Can't find end of Subexample layout")
2025 # check for consecutive layouts
2026 k = find_token(document.body, "\\begin_layout", j)
2027 if k == -1 or document.body[k] != "\\begin_layout Subexample":
2029 document.body[k : k + 1] = ["\\begin_layout Standard"] + put_cmd_in_ert("\\item ")
2030 j = find_end_of_layout(document.body, k)
2032 document.warning("Malformed LyX document: Can't find end of Subexample layout")
2036 endev = put_cmd_in_ert("\\end{subexamples}")
2038 document.body[j : j] = ["\\end_layout", "", "\\begin_layout Standard"] + endev
2039 document.body[i : i + 1] = ["\\begin_layout Standard"] + cmd \
2040 + ["\\end_layout", "", "\\begin_layout Standard"] + put_cmd_in_ert("\\item ")
2042 document.append_local_layout("Requires covington")
2047 def revert_drs(document):
2048 " Revert DRS insets (linguistics) to ERT "
2050 if not "linguistics" in document.get_module_list():
2054 drses = ["\\begin_inset Flex DRS", "\\begin_inset Flex DRS*",
2055 "\\begin_inset Flex IfThen-DRS", "\\begin_inset Flex Cond-DRS",
2056 "\\begin_inset Flex QDRS", "\\begin_inset Flex NegDRS",
2057 "\\begin_inset Flex SDRS"]
2061 i = find_token(document.body, drs, i)
2064 j = find_end_of_inset(document.body, i)
2066 document.warning("Malformed LyX document: Can't find end of DRS inset")
2070 # Check for arguments
2071 arg = find_token(document.body, "\\begin_inset Argument 1", i, j)
2072 endarg = find_end_of_inset(document.body, arg)
2075 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
2076 if argbeginPlain == -1:
2077 document.warning("Malformed LyX document: Can't find Argument 1 plain Layout")
2080 argendPlain = find_end_of_inset(document.body, argbeginPlain)
2081 prearg1content = document.body[argbeginPlain + 1 : argendPlain - 2]
2083 # remove Arg insets and paragraph, if it only contains this inset
2084 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
2085 del document.body[arg - 1 : endarg + 4]
2087 del document.body[arg : endarg + 1]
2090 j = find_end_of_inset(document.body, i)
2092 document.warning("Malformed LyX document: Can't find end of DRS inset")
2096 arg = find_token(document.body, "\\begin_inset Argument 2", i, j)
2097 endarg = find_end_of_inset(document.body, arg)
2100 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
2101 if argbeginPlain == -1:
2102 document.warning("Malformed LyX document: Can't find Argument 2 plain Layout")
2105 argendPlain = find_end_of_inset(document.body, argbeginPlain)
2106 prearg2content = document.body[argbeginPlain + 1 : argendPlain - 2]
2108 # remove Arg insets and paragraph, if it only contains this inset
2109 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
2110 del document.body[arg - 1 : endarg + 4]
2112 del document.body[arg : endarg + 1]
2115 j = find_end_of_inset(document.body, i)
2117 document.warning("Malformed LyX document: Can't find end of DRS inset")
2121 arg = find_token(document.body, "\\begin_inset Argument post:1", i, j)
2122 endarg = find_end_of_inset(document.body, arg)
2123 postarg1content = []
2125 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
2126 if argbeginPlain == -1:
2127 document.warning("Malformed LyX document: Can't find Argument post:1 plain Layout")
2130 argendPlain = find_end_of_inset(document.body, argbeginPlain)
2131 postarg1content = document.body[argbeginPlain + 1 : argendPlain - 2]
2133 # remove Arg insets and paragraph, if it only contains this inset
2134 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
2135 del document.body[arg - 1 : endarg + 4]
2137 del document.body[arg : endarg + 1]
2140 j = find_end_of_inset(document.body, i)
2142 document.warning("Malformed LyX document: Can't find end of DRS inset")
2146 arg = find_token(document.body, "\\begin_inset Argument post:2", i, j)
2147 endarg = find_end_of_inset(document.body, arg)
2148 postarg2content = []
2150 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
2151 if argbeginPlain == -1:
2152 document.warning("Malformed LyX document: Can't find Argument post:2 plain Layout")
2155 argendPlain = find_end_of_inset(document.body, argbeginPlain)
2156 postarg2content = document.body[argbeginPlain + 1 : argendPlain - 2]
2158 # remove Arg insets and paragraph, if it only contains this inset
2159 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
2160 del document.body[arg - 1 : endarg + 4]
2162 del document.body[arg : endarg + 1]
2165 j = find_end_of_inset(document.body, i)
2167 document.warning("Malformed LyX document: Can't find end of DRS inset")
2171 arg = find_token(document.body, "\\begin_inset Argument post:3", i, j)
2172 endarg = find_end_of_inset(document.body, arg)
2173 postarg3content = []
2175 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
2176 if argbeginPlain == -1:
2177 document.warning("Malformed LyX document: Can't find Argument post:3 plain Layout")
2180 argendPlain = find_end_of_inset(document.body, argbeginPlain)
2181 postarg3content = document.body[argbeginPlain + 1 : argendPlain - 2]
2183 # remove Arg insets and paragraph, if it only contains this inset
2184 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
2185 del document.body[arg - 1 : endarg + 4]
2187 del document.body[arg : endarg + 1]
2190 j = find_end_of_inset(document.body, i)
2192 document.warning("Malformed LyX document: Can't find end of DRS inset")
2196 arg = find_token(document.body, "\\begin_inset Argument post:4", i, j)
2197 endarg = find_end_of_inset(document.body, arg)
2198 postarg4content = []
2200 argbeginPlain = find_token(document.body, "\\begin_layout Plain Layout", arg, endarg)
2201 if argbeginPlain == -1:
2202 document.warning("Malformed LyX document: Can't find Argument post:4 plain Layout")
2205 argendPlain = find_end_of_inset(document.body, argbeginPlain)
2206 postarg4content = document.body[argbeginPlain + 1 : argendPlain - 2]
2208 # remove Arg insets and paragraph, if it only contains this inset
2209 if document.body[arg - 1] == "\\begin_layout Plain Layout" and find_end_of_layout(document.body, arg - 1) == endarg + 3:
2210 del document.body[arg - 1 : endarg + 4]
2212 del document.body[arg : endarg + 1]
2214 # The respective LaTeX command
2216 if drs == "\\begin_inset Flex DRS*":
2218 elif drs == "\\begin_inset Flex IfThen-DRS":
2220 elif drs == "\\begin_inset Flex Cond-DRS":
2222 elif drs == "\\begin_inset Flex QDRS":
2224 elif drs == "\\begin_inset Flex NegDRS":
2226 elif drs == "\\begin_inset Flex SDRS":
2229 beginPlain = find_token(document.body, "\\begin_layout Plain Layout", i)
2230 endInset = find_end_of_inset(document.body, i)
2231 endPlain = find_token_backwards(document.body, "\\end_layout", endInset)
2232 precontent = put_cmd_in_ert(cmd)
2233 precontent += put_cmd_in_ert("{") + prearg1content + put_cmd_in_ert("}")
2234 if drs == "\\begin_inset Flex SDRS":
2235 precontent += put_cmd_in_ert("{") + prearg2content + put_cmd_in_ert("}")
2236 precontent += put_cmd_in_ert("{")
2239 if cmd == "\\qdrs" or cmd == "\\condrs" or cmd == "\\ifdrs":
2240 postcontent = put_cmd_in_ert("}{") + postarg1content + put_cmd_in_ert("}{") + postarg2content + put_cmd_in_ert("}")
2241 if cmd == "\\condrs" or cmd == "\\qdrs":
2242 postcontent += put_cmd_in_ert("{") + postarg3content + put_cmd_in_ert("}")
2244 postcontent += put_cmd_in_ert("{") + postarg4content + put_cmd_in_ert("}")
2246 postcontent = put_cmd_in_ert("}")
2248 document.body[endPlain:endInset + 1] = postcontent
2249 document.body[beginPlain + 1:beginPlain] = precontent
2250 del document.body[i : beginPlain + 1]
2252 document.append_local_layout("Provides covington")
2253 add_to_preamble(document, ["\\usepackage{drs,covington}"])
2262 supported_versions = ["2.4.0", "2.4"]
2264 [545, [convert_lst_literalparam]],
2269 [550, [convert_fontenc]],
2276 [557, [convert_vcsinfo]],
2277 [558, [removeFrontMatterStyles]],
2280 [561, [convert_latexFonts]], # Handle dejavu, ibmplex fonts in GUI
2284 [565, [convert_AdobeFonts]], # Handle adobe fonts in GUI
2285 [566, [convert_hebrew_parentheses]],
2291 [572, [convert_notoFonts]], # Added options thin, light, extralight for Noto
2292 [573, [convert_inputencoding_namechange]],
2293 [574, [convert_ruby_module, convert_utf8_japanese]],
2294 [575, [convert_lineno]],
2296 [577, [convert_linggloss]],
2300 revert = [[576, [revert_drs]],
2301 [576, [revert_linggloss, revert_subexarg]],
2302 [575, [revert_new_languages]],
2303 [574, [revert_lineno]],
2304 [573, [revert_ruby_module, revert_utf8_japanese]],
2305 [572, [revert_inputencoding_namechange]],
2306 [571, [revert_notoFonts]],
2307 [570, [revert_cmidruletrimming]],
2308 [569, [revert_bibfileencodings]],
2309 [568, [revert_tablestyle]],
2310 [567, [revert_soul]],
2311 [566, [revert_malayalam]],
2312 [565, [revert_hebrew_parentheses]],
2313 [564, [revert_AdobeFonts]],
2314 [563, [revert_lformatinfo]],
2315 [562, [revert_listpargs]],
2316 [561, [revert_l7ninfo]],
2317 [560, [revert_latexFonts]], # Handle dejavu, ibmplex fonts in user preamble
2318 [559, [revert_timeinfo, revert_namenoextinfo]],
2319 [558, [revert_dateinfo]],
2320 [557, [addFrontMatterStyles]],
2321 [556, [revert_vcsinfo]],
2322 [555, [revert_bibencoding]],
2323 [554, [revert_vcolumns]],
2324 [553, [revert_stretchcolumn]],
2325 [552, [revert_tuftecite]],
2326 [551, [revert_floatpclass, revert_floatalignment]],
2327 [550, [revert_nospellcheck]],
2328 [549, [revert_fontenc]],
2329 [548, []],# dummy format change
2330 [547, [revert_lscape]],
2331 [546, [revert_xcharter]],
2332 [545, [revert_paratype]],
2333 [544, [revert_lst_literalparam]]
2337 if __name__ == "__main__":