]> git.lyx.org Git - features.git/blob - lib/lyx2lyx/lyx_2_4.py
Added latex-DejaVu fonts to lyx-GUI.
[features.git] / lib / lyx2lyx / lyx_2_4.py
1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # Copyright (C) 2018 The LyX team
4 #
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.
9 #
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.
14 #
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.
18
19 """ Convert files to the file format generated by lyx 2.4"""
20
21 import re, string
22 import unicodedata
23 import sys, os
24
25 from datetime import (datetime, date, time)
26
27 # Uncomment only what you need to import, please.
28
29 from parser_tools import (count_pars_in_inset, find_end_of_inset, find_end_of_layout,
30 find_token, get_bool_value, get_option_value, get_value, get_quoted_value)
31 #    del_token, del_value, del_complete_lines,
32 #    find_complete_lines, find_end_of,
33 #    find_re, find_substring, find_token_backwards,
34 #    get_containing_inset, get_containing_layout,
35 #    is_in_inset, set_bool_value
36 #    find_tokens, find_token_exact, check_token
37
38 from lyx2lyx_tools import (put_cmd_in_ert, add_to_preamble)
39 #  revert_font_attrs, insert_to_preamble, latex_length
40 #  get_ert, lyx2latex, lyx2verbatim, length_in_bp, convert_info_insets
41 #  revert_flex_inset, hex2ratio, str2bool
42
43 ####################################################################
44 # Private helper functions
45
46
47
48 ###############################################################################
49 ###
50 ### Conversion and reversion routines
51 ###
52 ###############################################################################
53
54 def revert_dejavu(document):
55     " Revert native DejaVu font definition to LaTeX "
56
57     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
58         dejavu_fonts = ['DejaVuSerif', 'DejaVuSerifCondensed', 'DejaVuSans',
59                          'DejaVuSansMono', 'DejaVuSansCondensed']
60         font_types = ["\\font_roman", "\\font_sans,sf", "\\font_typewriter,tt"]
61         for ft1 in font_types:
62             fts = ft1.split(",")
63             ft = fts[0]
64             i = find_token(document.header, ft, 0)
65             if i != -1:
66                 val = get_value(document.header, ft, i)
67                 words = val.split()
68                 val = words[0].replace('"', '')
69                 if val in dejavu_fonts:
70                     xoption = ""
71                     document.header[i] = ft + ' "default" ' + words[1]
72                     if len(fts) > 1:
73                         xval =  get_value(document.header, "\\font_" + fts[1] + "_scale", 0)
74                         # cutoff " 100"
75                         xval = xval[:-4]
76                         if xval != "100":
77                             xoption = "[scaled=" + format(float(xval) / 100, '.2f') + "]"
78                     preamble = "\\usepackage" + xoption + "{%s}" % val
79                     add_to_preamble(document, [preamble])
80
81 def removeFrontMatterStyles(document):
82     " Remove styles Begin/EndFromatter"
83
84     layouts = ['BeginFrontmatter', 'EndFrontmatter']
85     for layout in layouts:
86         i = 0
87         while True:
88             i = find_token(document.body, '\\begin_layout ' + layout, i)
89             if i == -1:
90                 break
91             j = find_end_of_layout(document.body, i)
92             if j == -1:
93                 document.warning("Malformed LyX document: Can't find end of layout at line %d" % i)
94                 i += 1
95                 continue
96             while i > 0 and document.body[i-1].strip() == '':
97                 i -= 1
98             while document.body[j+1].strip() == '':
99                 j = j + 1
100             document.body[i:j+1] = ['']
101
102 def addFrontMatterStyles(document):
103     " Use styles Begin/EndFrontmatter for elsarticle"
104
105     def insertFrontmatter(prefix, line):
106         above = line
107         while above > 0 and document.body[above-1].strip() == '':
108             above -= 1
109         below = line
110         while document.body[below].strip() == '':
111             below += 1
112         document.body[above:below] = ['', '\\begin_layout ' + prefix + 'Frontmatter',
113                                     '\\begin_inset Note Note',
114                                     'status open', '',
115                                     '\\begin_layout Plain Layout',
116                                     'Keep this empty!',
117                                     '\\end_layout', '',
118                                     '\\end_inset', '', '',
119                                     '\\end_layout', '']
120
121     if document.textclass == "elsarticle":
122         layouts = ['Title', 'Title footnote', 'Author', 'Author footnote',
123                    'Corresponding author', 'Address', 'Email', 'Abstract', 'Keywords']
124         first = -1
125         last = -1
126         for layout in layouts:
127             i = 0
128             while True:
129                 i = find_token(document.body, '\\begin_layout ' + layout, i)
130                 if i == -1:
131                     break
132                 k = find_end_of_layout(document.body, i)
133                 if k == -1:
134                     document.warning("Malformed LyX document: Can't find end of layout at line %d" % i)
135                     i += 1;
136                     continue
137                 if first == -1 or i < first:
138                     first = i
139                 if last == -1 or last <= k:
140                     last = k+1
141                 i = k+1
142         if first == -1:
143             return
144         insertFrontmatter('End', last)
145         insertFrontmatter('Begin', first)
146
147 def convert_lst_literalparam(document):
148     " Add param literal to include inset "
149
150     i = 0
151     while True:
152         i = find_token(document.body, '\\begin_inset CommandInset include', i)
153         if i == -1:
154             break
155         j = find_end_of_inset(document.body, i)
156         if j == -1:
157             document.warning("Malformed LyX document: Can't find end of command inset at line %d" % i)
158             i += 1
159             continue
160         while i < j and document.body[i].strip() != '':
161             i += 1
162         document.body.insert(i, "literal \"true\"")
163
164
165 def revert_lst_literalparam(document):
166     " Remove param literal from include inset "
167
168     i = 0
169     while True:
170         i = find_token(document.body, '\\begin_inset CommandInset include', i)
171         if i == -1:
172             break
173         j = find_end_of_inset(document.body, i)
174         if j == -1:
175             document.warning("Malformed LyX document: Can't find end of include inset at line %d" % i)
176             i += 1
177             continue
178         k = find_token(document.body, 'literal', i, j)
179         if k == -1:
180             i += 1
181             continue
182         del document.body[k]
183
184
185 def revert_paratype(document):
186     " Revert ParaType font definitions to LaTeX "
187
188     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
189         preamble = ""
190         i1 = find_token(document.header, "\\font_roman \"PTSerif-TLF\"", 0)
191         i2 = find_token(document.header, "\\font_sans \"default\"", 0)
192         i3 = find_token(document.header, "\\font_typewriter \"default\"", 0)
193         j = find_token(document.header, "\\font_sans \"PTSans-TLF\"", 0)
194         sfval = get_value(document.header, "\\font_sf_scale", 0)
195         # cutoff " 100"
196         sfval = sfval[:-4]
197         sfoption = ""
198         if sfval != "100":
199             sfoption = "scaled=" + format(float(sfval) / 100, '.2f')
200         k = find_token(document.header, "\\font_typewriter \"PTMono-TLF\"", 0)
201         ttval = get_value(document.header, "\\font_tt_scale", 0)
202         # cutoff " 100"
203         ttval = ttval[:-4]
204         ttoption = ""
205         if ttval != "100":
206             ttoption = "scaled=" + format(float(ttval) / 100, '.2f')
207         if i1 != -1 and i2 != -1 and i3!= -1:
208             add_to_preamble(document, ["\\usepackage{paratype}"])
209         else:
210             if i1!= -1:
211                 add_to_preamble(document, ["\\usepackage{PTSerif}"])
212                 document.header[i1] = document.header[i1].replace("PTSerif-TLF", "default")
213             if j!= -1:
214                 if sfoption != "":
215                     add_to_preamble(document, ["\\usepackage[" + sfoption + "]{PTSans}"])
216                 else:
217                     add_to_preamble(document, ["\\usepackage{PTSans}"])
218                 document.header[j] = document.header[j].replace("PTSans-TLF", "default")
219             if k!= -1:
220                 if ttoption != "":
221                     add_to_preamble(document, ["\\usepackage[" + ttoption + "]{PTMono}"])
222                 else:
223                     add_to_preamble(document, ["\\usepackage{PTMono}"])
224                 document.header[k] = document.header[k].replace("PTMono-TLF", "default")
225
226
227 def revert_xcharter(document):
228     " Revert XCharter font definitions to LaTeX "
229
230     i = find_token(document.header, "\\font_roman \"xcharter\"", 0)
231     if i == -1:
232         return
233
234     # replace unsupported font setting
235     document.header[i] = document.header[i].replace("xcharter", "default")
236     # no need for preamble code with system fonts
237     if get_bool_value(document.header, "\\use_non_tex_fonts"):
238         return
239
240     # transfer old style figures setting to package options
241     j = find_token(document.header, "\\font_osf true")
242     if j != -1:
243         options = "[osf]"
244         document.header[j] = "\\font_osf false"
245     else:
246         options = ""
247     if i != -1:
248         add_to_preamble(document, ["\\usepackage%s{XCharter}"%options])
249
250
251 def revert_lscape(document):
252     " Reverts the landscape environment (Landscape module) to TeX-code "
253
254     if not "landscape" in document.get_module_list():
255         return
256
257     i = 0
258     while True:
259         i = find_token(document.body, "\\begin_inset Flex Landscape", i)
260         if i == -1:
261             return
262         j = find_end_of_inset(document.body, i)
263         if j == -1:
264             document.warning("Malformed LyX document: Can't find end of Landscape inset")
265             i += 1
266             continue
267
268         if document.body[i] == "\\begin_inset Flex Landscape (Floating)":
269             document.body[j - 2 : j + 1] = put_cmd_in_ert("\\end{landscape}}")
270             document.body[i : i + 4] = put_cmd_in_ert("\\afterpage{\\begin{landscape}")
271             add_to_preamble(document, ["\\usepackage{afterpage}"])
272         else:
273             document.body[j - 2 : j + 1] = put_cmd_in_ert("\\end{landscape}")
274             document.body[i : i + 4] = put_cmd_in_ert("\\begin{landscape}")
275
276         add_to_preamble(document, ["\\usepackage{pdflscape}"])
277         # no need to reset i
278
279
280 def convert_fontenc(document):
281     " Convert default fontenc setting "
282
283     i = find_token(document.header, "\\fontencoding global", 0)
284     if i == -1:
285         return
286
287     document.header[i] = document.header[i].replace("global", "auto")
288
289
290 def revert_fontenc(document):
291     " Revert default fontenc setting "
292
293     i = find_token(document.header, "\\fontencoding auto", 0)
294     if i == -1:
295         return
296
297     document.header[i] = document.header[i].replace("auto", "global")
298
299
300 def revert_nospellcheck(document):
301     " Remove nospellcheck font info param "
302
303     i = 0
304     while True:
305         i = find_token(document.body, '\\nospellcheck', i)
306         if i == -1:
307             return
308         del document.body[i]
309
310
311 def revert_floatpclass(document):
312     " Remove float placement params 'document' and 'class' "
313
314     i = 0
315     i = find_token(document.header, "\\float_placement class", 0)
316     if i != -1:
317         del document.header[i]
318
319     i = 0
320     while True:
321         i = find_token(document.body, '\\begin_inset Float', i)
322         if i == -1:
323             break
324         j = find_end_of_inset(document.body, i)
325         k = find_token(document.body, 'placement class', i, i + 2)
326         if k == -1:
327             k = find_token(document.body, 'placement document', i, i + 2)
328             if k != -1:
329                 del document.body[k]
330             i = j
331             continue
332         del document.body[k]
333
334
335 def revert_floatalignment(document):
336     " Remove float alignment params "
337
338     i = 0
339     i = find_token(document.header, "\\float_alignment", 0)
340     galignment = ""
341     if i != -1:
342         galignment = get_value(document.header, "\\float_alignment", i)
343         del document.header[i]
344
345     i = 0
346     while True:
347         i = find_token(document.body, '\\begin_inset Float', i)
348         if i == -1:
349             break
350         j = find_end_of_inset(document.body, i)
351         if j == -1:
352             document.warning("Malformed LyX document: Can't find end of inset at line " + str(i))
353             i += 1
354         k = find_token(document.body, 'alignment', i, i + 4)
355         if k == -1:
356             i = j
357             continue
358         alignment = get_value(document.body, "alignment", k)
359         if alignment == "document":
360             alignment = galignment
361         del document.body[k]
362         l = find_token(document.body, "\\begin_layout Plain Layout", i, j)
363         if l == -1:
364             document.warning("Can't find float layout!")
365             i = j
366             continue
367         alcmd = []
368         if alignment == "left":
369             alcmd = put_cmd_in_ert("\\raggedright{}")
370         elif alignment == "center":
371             alcmd = put_cmd_in_ert("\\centering{}")
372         elif alignment == "right":
373             alcmd = put_cmd_in_ert("\\raggedleft{}")
374         if len(alcmd) > 0:
375             document.body[l+1:l+1] = alcmd
376         i = j 
377
378
379 def revert_tuftecite(document):
380     " Revert \cite commands in tufte classes "
381
382     tufte = ["tufte-book", "tufte-handout"]
383     if document.textclass not in tufte:
384         return
385
386     i = 0
387     while (True):
388         i = find_token(document.body, "\\begin_inset CommandInset citation", i)
389         if i == -1:
390             break
391         j = find_end_of_inset(document.body, i)
392         if j == -1:
393             document.warning("Can't find end of citation inset at line %d!!" %(i))
394             i += 1
395             continue
396         k = find_token(document.body, "LatexCommand", i, j)
397         if k == -1:
398             document.warning("Can't find LatexCommand for citation inset at line %d!" %(i))
399             i = j + 1
400             continue
401         cmd = get_value(document.body, "LatexCommand", k)
402         if cmd != "cite":
403             i = j + 1
404             continue
405         pre = get_quoted_value(document.body, "before", i, j)
406         post = get_quoted_value(document.body, "after", i, j)
407         key = get_quoted_value(document.body, "key", i, j)
408         if not key:
409             document.warning("Citation inset at line %d does not have a key!" %(i))
410             key = "???"
411         # Replace command with ERT
412         res = "\\cite"
413         if pre:
414             res += "[" + pre + "]"
415         if post:
416             res += "[" + post + "]"
417         elif pre:
418             res += "[]"
419         res += "{" + key + "}"
420         document.body[i:j+1] = put_cmd_in_ert([res])
421         i = j + 1
422
423
424 def revert_stretchcolumn(document):
425     " We remove the column varwidth flags or everything else will become a mess. "
426     i = 0
427     while True:
428         i = find_token(document.body, "\\begin_inset Tabular", i)
429         if i == -1:
430             return
431         j = find_end_of_inset(document.body, i + 1)
432         if j == -1:
433             document.warning("Malformed LyX document: Could not find end of tabular.")
434             continue
435         for k in range(i, j):
436             if re.search('^<column.*varwidth="[^"]+".*>$', document.body[k]):
437                 document.warning("Converting 'tabularx'/'xltabular' table to normal table.")
438                 document.body[k] = document.body[k].replace(' varwidth="true"', '')
439         i = i + 1
440
441
442 def revert_vcolumns(document):
443     " Revert standard columns with line breaks etc. "
444     i = 0
445     needvarwidth = False
446     needarray = False
447     try:
448         while True:
449             i = find_token(document.body, "\\begin_inset Tabular", i)
450             if i == -1:
451                 return
452             j = find_end_of_inset(document.body, i)
453             if j == -1:
454                 document.warning("Malformed LyX document: Could not find end of tabular.")
455                 i += 1
456                 continue
457
458             # Collect necessary column information
459             m = i + 1
460             nrows = int(document.body[i+1].split('"')[3])
461             ncols = int(document.body[i+1].split('"')[5])
462             col_info = []
463             for k in range(ncols):
464                 m = find_token(document.body, "<column", m)
465                 width = get_option_value(document.body[m], 'width')
466                 varwidth = get_option_value(document.body[m], 'varwidth')
467                 alignment = get_option_value(document.body[m], 'alignment')
468                 special = get_option_value(document.body[m], 'special')
469                 col_info.append([width, varwidth, alignment, special, m])
470
471             # Now parse cells
472             m = i + 1
473             lines = []
474             for row in range(nrows):
475                 for col in range(ncols):
476                     m = find_token(document.body, "<cell", m)
477                     multicolumn = get_option_value(document.body[m], 'multicolumn')
478                     multirow = get_option_value(document.body[m], 'multirow')
479                     width = get_option_value(document.body[m], 'width')
480                     rotate = get_option_value(document.body[m], 'rotate')
481                     # Check for: linebreaks, multipars, non-standard environments
482                     begcell = m
483                     endcell = find_token(document.body, "</cell>", begcell)
484                     vcand = False
485                     if find_token(document.body, "\\begin_inset Newline", begcell, endcell) != -1:
486                         vcand = True
487                     elif count_pars_in_inset(document.body, begcell + 2) > 1:
488                         vcand = True
489                     elif get_value(document.body, "\\begin_layout", begcell) != "Plain Layout":
490                         vcand = True
491                     if vcand and rotate == "" and ((multicolumn == "" and multirow == "") or width == ""):
492                         if col_info[col][0] == "" and col_info[col][1] == "" and col_info[col][3] == "":
493                             needvarwidth = True
494                             alignment = col_info[col][2]
495                             col_line = col_info[col][4]
496                             vval = ""
497                             if alignment == "center":
498                                 vval = ">{\\centering}"
499                             elif  alignment == "left":
500                                 vval = ">{\\raggedright}"
501                             elif alignment == "right":
502                                 vval = ">{\\raggedleft}"
503                             if vval != "":
504                                 needarray = True
505                             vval += "V{\\linewidth}"
506                 
507                             document.body[col_line] = document.body[col_line][:-1] + " special=\"" + vval + "\">"
508                             # ERT newlines and linebreaks (since LyX < 2.4 automatically inserts parboxes
509                             # with newlines, and we do not want that)
510                             while True:
511                                 endcell = find_token(document.body, "</cell>", begcell)
512                                 linebreak = False
513                                 nl = find_token(document.body, "\\begin_inset Newline newline", begcell, endcell)
514                                 if nl == -1:
515                                     nl = find_token(document.body, "\\begin_inset Newline linebreak", begcell, endcell)
516                                     if nl == -1:
517                                          break
518                                     linebreak = True
519                                 nle = find_end_of_inset(document.body, nl)
520                                 del(document.body[nle:nle+1])
521                                 if linebreak:
522                                     document.body[nl:nl+1] = put_cmd_in_ert("\\linebreak{}")
523                                 else:
524                                     document.body[nl:nl+1] = put_cmd_in_ert("\\\\")
525                     m += 1
526
527             i = j + 1
528
529     finally:
530         if needarray == True:
531             add_to_preamble(document, ["\\usepackage{array}"])
532         if needvarwidth == True:
533             add_to_preamble(document, ["\\usepackage{varwidth}"])
534
535
536 def revert_bibencoding(document):
537     " Revert bibliography encoding "
538
539     # Get cite engine
540     engine = "basic"
541     i = find_token(document.header, "\\cite_engine", 0)
542     if i == -1:
543         document.warning("Malformed document! Missing \\cite_engine")
544     else:
545         engine = get_value(document.header, "\\cite_engine", i)
546
547     # Check if biblatex
548     biblatex = False
549     if engine in ["biblatex", "biblatex-natbib"]:
550         biblatex = True
551
552     # Map lyx to latex encoding names 
553     encodings = {
554         "utf8" : "utf8",
555         "utf8x" : "utf8x",
556         "armscii8" : "armscii8",
557         "iso8859-1" : "latin1",
558         "iso8859-2" : "latin2",
559         "iso8859-3" : "latin3",
560         "iso8859-4" : "latin4",
561         "iso8859-5" : "iso88595",
562         "iso8859-6" : "8859-6",
563         "iso8859-7" : "iso-8859-7",
564         "iso8859-8" : "8859-8",
565         "iso8859-9" : "latin5",
566         "iso8859-13" : "latin7",
567         "iso8859-15" : "latin9",
568         "iso8859-16" : "latin10",
569         "applemac" : "applemac",
570         "cp437" : "cp437",
571         "cp437de" : "cp437de",
572         "cp850" : "cp850",
573         "cp852" : "cp852",
574         "cp855" : "cp855",
575         "cp858" : "cp858",
576         "cp862" : "cp862",
577         "cp865" : "cp865",
578         "cp866" : "cp866",
579         "cp1250" : "cp1250",
580         "cp1251" : "cp1251",
581         "cp1252" : "cp1252",
582         "cp1255" : "cp1255",
583         "cp1256" : "cp1256",
584         "cp1257" : "cp1257",
585         "koi8-r" : "koi8-r",
586         "koi8-u" : "koi8-u",
587         "pt154" : "pt154",
588         "utf8-platex" : "utf8",
589         "ascii" : "ascii"
590     }
591
592     i = 0
593     bibresources = []
594     while (True):
595         i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
596         if i == -1:
597             break
598         j = find_end_of_inset(document.body, i)
599         if j == -1:
600             document.warning("Can't find end of bibtex inset at line %d!!" %(i))
601             i += 1
602             continue
603         encoding = get_quoted_value(document.body, "encoding", i, j)
604         if not encoding:
605             i += 1
606             continue
607         # remove encoding line
608         k = find_token(document.body, "encoding", i, j)
609         if k != -1:
610             del document.body[k]
611         # Re-find inset end line
612         j = find_end_of_inset(document.body, i)
613         if biblatex:
614             biblio_options = ""
615             h = find_token(document.header, "\\biblio_options", 0)
616             if h != -1:
617                 biblio_options = get_value(document.header, "\\biblio_options", h)
618                 if not "bibencoding" in biblio_options:
619                      document.header[h] += ",bibencoding=%s" % encodings[encoding]
620             else:
621                 bs = find_token(document.header, "\\biblatex_bibstyle", 0)
622                 if bs == -1:
623                     # this should not happen
624                     document.warning("Malformed LyX document! No \\biblatex_bibstyle header found!")
625                 else:
626                     document.header[bs-1 : bs-1] = ["\\biblio_options bibencoding=" + encodings[encoding]]
627         else:
628             document.body[j+1:j+1] = put_cmd_in_ert("\\egroup")
629             document.body[i:i] = put_cmd_in_ert("\\bgroup\\inputencoding{" + encodings[encoding] + "}")
630
631         i = j + 1
632
633
634
635 def convert_vcsinfo(document):
636     " Separate vcs Info inset from buffer Info inset. "
637
638     types = {
639         "vcs-revision" : "revision",
640         "vcs-tree-revision" : "tree-revision",
641         "vcs-author" : "author",
642         "vcs-time" : "time",
643         "vcs-date" : "date"
644     }
645     i = 0
646     while True:
647         i = find_token(document.body, "\\begin_inset Info", i)
648         if i == -1:
649             return
650         j = find_end_of_inset(document.body, i + 1)
651         if j == -1:
652             document.warning("Malformed LyX document: Could not find end of Info inset.")
653             i = i + 1
654             continue
655         tp = find_token(document.body, 'type', i, j)
656         tpv = get_quoted_value(document.body, "type", tp)
657         if tpv != "buffer":
658             i = i + 1
659             continue
660         arg = find_token(document.body, 'arg', i, j)
661         argv = get_quoted_value(document.body, "arg", arg)
662         if argv not in list(types.keys()):
663             i = i + 1
664             continue
665         document.body[tp] = "type \"vcs\""
666         document.body[arg] = "arg \"" + types[argv] + "\""
667         i = i + 1
668
669
670 def revert_vcsinfo(document):
671     " Merge vcs Info inset to buffer Info inset. "
672
673     args = ["revision", "tree-revision", "author", "time", "date" ]
674     i = 0
675     while True:
676         i = find_token(document.body, "\\begin_inset Info", i)
677         if i == -1:
678             return
679         j = find_end_of_inset(document.body, i + 1)
680         if j == -1:
681             document.warning("Malformed LyX document: Could not find end of Info inset.")
682             i = i + 1
683             continue
684         tp = find_token(document.body, 'type', i, j)
685         tpv = get_quoted_value(document.body, "type", tp)
686         if tpv != "vcs":
687             i = i + 1
688             continue
689         arg = find_token(document.body, 'arg', i, j)
690         argv = get_quoted_value(document.body, "arg", arg)
691         if argv not in args:
692             document.warning("Malformed Info inset. Invalid vcs arg.")
693             i = i + 1
694             continue
695         document.body[tp] = "type \"buffer\""
696         document.body[arg] = "arg \"vcs-" + argv + "\""
697         i = i + 1
698
699
700 def revert_dateinfo(document):
701     " Revert date info insets to static text. "
702
703 # FIXME This currently only considers the main language and uses the system locale
704 # Ideally, it should honor context languages and switch the locale accordingly.
705
706     # The date formats for each language using strftime syntax:
707     # long, short, loclong, locmedium, locshort
708     dateformats = {
709         "afrikaans" : ["%A, %d %B %Y", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y/%m/%d"],
710         "albanian" : ["%A, %d %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
711         "american" : ["%A, %B %d, %Y", "%m/%d/%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
712         "amharic" : ["%A ፣%d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
713         "ancientgreek" : ["%A, %d %B %Y", "%d %b %Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
714         "arabic_arabi" : ["%A، %d %B، %Y", "%d‏/%m‏/%Y", "%d %B، %Y", "%d/%m/%Y", "%d/%m/%Y"],
715         "arabic_arabtex" : ["%A، %d %B، %Y", "%d‏/%m‏/%Y", "%d %B، %Y", "%d/%m/%Y", "%d/%m/%Y"],
716         "armenian" : ["%Y թ. %B %d, %A", "%d.%m.%y", "%d %B، %Y", "%d %b، %Y", "%d/%m/%Y"],
717         "asturian" : ["%A, %d %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d %b %Y", "%d/%m/%Y"],
718         "australian" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
719         "austrian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
720         "bahasa" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
721         "bahasam" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
722         "basque" : ["%Y(e)ko %B %d, %A", "%y/%m/%d", "%Y %B %d", "%Y %b %d", "%Y/%m/%d"],
723         "belarusian" : ["%A, %d %B %Y г.", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
724         "bosnian" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%Y-%m-%d"],
725         "brazilian" : ["%A, %d de %B de %Y", "%d/%m/%Y", "%d de %B de %Y", "%d de %b de %Y", "%d/%m/%Y"],
726         "breton" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
727         "british" : ["%A, %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
728         "bulgarian" : ["%A, %d %B %Y г.", "%d.%m.%y г.", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
729         "canadian" : ["%A, %B %d, %Y", "%Y-%m-%d", "%B %d, %Y", "%d %b %Y", "%Y-%m-%d"],
730         "canadien" : ["%A %d %B %Y", "%y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
731         "catalan" : ["%A, %d %B de %Y", "%d/%m/%y", "%d / %B / %Y", "%d / %b / %Y", "%d/%m/%Y"],
732         "chinese-simplified" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y-%m-%d", "%y-%m-%d"],
733         "chinese-traditional" : ["%Y年%m月%d日 %A", "%Y/%m/%d", "%Y年%m月%d日", "%Y年%m月%d日", "%y年%m月%d日"],
734         "coptic" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
735         "croatian" : ["%A, %d. %B %Y.", "%d. %m. %Y.", "%d. %B %Y.", "%d. %b. %Y.", "%d.%m.%Y."],
736         "czech" : ["%A %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b. %Y", "%d.%m.%Y"],
737         "danish" : ["%A den %d. %B %Y", "%d/%m/%Y", "%d. %B %Y", "%d. %b %Y", "%d/%m/%Y"],
738         "divehi" : ["%Y %B %d, %A", "%Y-%m-%d", "%Y %B %d", "%Y %b %d", "%d/%m/%Y"],
739         "dutch" : ["%A %d %B %Y", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
740         "english" : ["%A, %B %d, %Y", "%m/%d/%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
741         "esperanto" : ["%A, %d %B %Y", "%d %b %Y", "la %d de %B %Y", "la %d de %b %Y", "%m/%d/%Y"],
742         "estonian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
743         "farsi" : ["%A %d %B %Y", "%Y/%m/%d", "%d %B %Y", "%d %b %Y", "%Y/%m/%d"],
744         "finnish" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
745         "french" : ["%A %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
746         "friulan" : ["%A %d di %B dal %Y", "%d/%m/%y", "%d di %B dal %Y", "%d di %b dal %Y", "%d/%m/%Y"],
747         "galician" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d de %b de %Y", "%d/%m/%Y"],
748         "georgian" : ["%A, %d %B, %Y", "%d.%m.%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
749         "german" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
750         "german-ch" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
751         "german-ch-old" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
752         "greek" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
753         "hebrew" : ["%A, %d ב%B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
754         "hindi" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
755         "icelandic" : ["%A, %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
756         "interlingua" : ["%Y %B %d, %A", "%Y-%m-%d", "le %d de %B %Y", "le %d de %b %Y", "%Y-%m-%d"],
757         "irish" : ["%A %d %B %Y", "%d/%m/%Y", "%d. %B %Y", "%d. %b %Y", "%d/%m/%Y"],
758         "italian" : ["%A %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d/%b/%Y", "%d/%m/%Y"],
759         "japanese" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y/%m/%d", "%y/%m/%d"],
760         "japanese-cjk" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y/%m/%d", "%y/%m/%d"],
761         "kannada" : ["%A, %B %d, %Y", "%d/%m/%y", "%d %B %Y", "%d %B %Y", "%d-%m-%Y"],
762         "kazakh" : ["%Y ж. %d %B, %A", "%d.%m.%y", "%d %B %Y", "%d %B %Y", "%Y-%d-%m"],
763         "khmer" : ["%A %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %B %Y", "%d/%m/%Y"],
764         "korean" : ["%Y년 %m월 %d일 %A", "%y. %m. %d.", "%Y년 %m월 %d일", "%Y. %m. %d.", "%y. %m. %d."],
765         "kurmanji" : ["%A, %d %B %Y", "%d %b %Y", "%d. %B %Y", "%d. %m. %Y", "%Y-%m-%d"],
766         "lao" : ["%A ທີ %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %B %Y", "%d/%m/%Y"],
767         "latin" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
768         "latvian" : ["%A, %Y. gada %d. %B", "%d.%m.%y", "%Y. gada %d. %B", "%Y. gada %d. %b", "%d.%m.%Y"],
769         "lithuanian" : ["%Y m. %B %d d., %A", "%Y-%m-%d", "%Y m. %B %d d.", "%Y m. %B %d d.", "%Y-%m-%d"],
770         "lowersorbian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
771         "macedonian" : ["%A, %d %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
772         "magyar" : ["%Y. %B %d., %A", "%Y. %m. %d.", "%Y. %B %d.", "%Y. %b %d.", "%Y.%m.%d."],
773         "marathi" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
774         "mongolian" : ["%A, %Y оны %m сарын %d", "%Y-%m-%d", "%Y оны %m сарын %d", "%d-%m-%Y", "%d-%m-%Y"],
775         "naustrian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
776         "newzealand" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
777         "ngerman" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
778         "norsk" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
779         "nynorsk" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
780         "occitan" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
781         "piedmontese" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
782         "polish" : ["%A, %d %B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
783         "polutonikogreek" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
784         "portuguese" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d de %b de %Y", "%Y/%m/%d"],
785         "romanian" : ["%A, %d %B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
786         "romansh" : ["%A, ils %d da %B %Y", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
787         "russian" : ["%A, %d %B %Y г.", "%d.%m.%Y", "%d %B %Y г.", "%d %b %Y г.", "%d.%m.%Y"],
788         "samin" : ["%Y %B %d, %A", "%Y-%m-%d", "%B %d. b. %Y", "%b %d. b. %Y", "%d.%m.%Y"],
789         "sanskrit" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
790         "scottish" : ["%A, %dmh %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
791         "serbian" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
792         "serbian-latin" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
793         "slovak" : ["%A, %d. %B %Y", "%d. %m. %Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
794         "slovene" : ["%A, %d. %B %Y", "%d. %m. %y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
795         "spanish" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B %de %Y", "%d %b %Y", "%d/%m/%Y"],
796         "spanish-mexico" : ["%A, %d de %B %de %Y", "%d/%m/%y", "%d de %B de %Y", "%d %b %Y", "%d/%m/%Y"],
797         "swedish" : ["%A %d %B %Y", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
798         "syriac" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
799         "tamil" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
800         "telugu" : ["%d, %B %Y, %A", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
801         "thai" : ["%Aที่ %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
802         "tibetan" : ["%Y %Bའི་ཚེས་%d, %A", "%Y-%m-%d", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
803         "turkish" : ["%d %B %Y %A", "%d.%m.%Y", "%d %B %Y", "%d.%b.%Y", "%d.%m.%Y"],
804         "turkmen" : ["%d %B %Y %A", "%d.%m.%Y", "%Y ý. %B %d", "%d.%m.%Y ý.", "%d.%m.%y ý."],
805         "ukrainian" : ["%A, %d %B %Y р.", "%d.%m.%y", "%d %B %Y", "%d %m %Y", "%d.%m.%Y"],
806         "uppersorbian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
807         "urdu" : ["%A، %d %B، %Y", "%d/%m/%y", "%d %B, %Y", "%d %b %Y", "%d/%m/%Y"],
808         "vietnamese" : ["%A, %d %B, %Y", "%d/%m/%Y", "%d tháng %B %Y", "%d-%m-%Y", "%d/%m/%Y"],
809         "welsh" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
810     }
811
812     types = ["date", "fixdate", "moddate" ]
813     i = 0
814     i = find_token(document.header, "\\language", 0)
815     if i == -1:
816         # this should not happen
817         document.warning("Malformed LyX document! No \\language header found!")
818         return
819     lang = get_value(document.header, "\\language", i)
820
821     i = 0
822     while True:
823         i = find_token(document.body, "\\begin_inset Info", i)
824         if i == -1:
825             return
826         j = find_end_of_inset(document.body, i + 1)
827         if j == -1:
828             document.warning("Malformed LyX document: Could not find end of Info inset.")
829             i = i + 1
830             continue
831         tp = find_token(document.body, 'type', i, j)
832         tpv = get_quoted_value(document.body, "type", tp)
833         if tpv not in types:
834             i = i + 1
835             continue
836         arg = find_token(document.body, 'arg', i, j)
837         argv = get_quoted_value(document.body, "arg", arg)
838         isodate = ""
839         dte = date.today()
840         if tpv == "fixdate":
841             datecomps = argv.split('@')
842             if len(datecomps) > 1:
843                 argv = datecomps[0]
844                 isodate = datecomps[1]
845                 m = re.search('(\d\d\d\d)-(\d\d)-(\d\d)', isodate)
846                 if m:
847                     dte = date(int(m.group(1)), int(m.group(2)), int(m.group(3)))
848 # FIXME if we had the path to the original document (not the one in the tmp dir),
849 #        we could use the mtime.
850 #        elif tpv == "moddate":
851 #            dte = date.fromtimestamp(os.path.getmtime(document.dir))
852         result = ""
853         if argv == "ISO":
854             result = dte.isodate()
855         elif argv == "long":
856             result = dte.strftime(dateformats[lang][0])
857         elif argv == "short":
858             result = dte.strftime(dateformats[lang][1])
859         elif argv == "loclong":
860             result = dte.strftime(dateformats[lang][2])
861         elif argv == "locmedium":
862             result = dte.strftime(dateformats[lang][3])
863         elif argv == "locshort":
864             result = dte.strftime(dateformats[lang][4])
865         else:
866             fmt = argv.replace("MMMM", "%b").replace("MMM", "%b").replace("MM", "%m").replace("M", "%m")
867             fmt = fmt.replace("yyyy", "%Y").replace("yy", "%y")
868             fmt = fmt.replace("dddd", "%A").replace("ddd", "%a").replace("dd", "%d")
869             fmt = re.sub('[^\'%]d', '%d', fmt)
870             fmt = fmt.replace("'", "")
871             result = dte.strftime(fmt)
872         document.body[i : j+1] = result
873         i = i + 1
874
875
876 def revert_timeinfo(document):
877     " Revert time info insets to static text. "
878
879 # FIXME This currently only considers the main language and uses the system locale
880 # Ideally, it should honor context languages and switch the locale accordingly.
881 # Also, the time object is "naive", i.e., it does not know of timezones (%Z will
882 # be empty).
883
884     # The time formats for each language using strftime syntax:
885     # long, short
886     timeformats = {
887         "afrikaans" : ["%H:%M:%S %Z", "%H:%M"],
888         "albanian" : ["%I:%M:%S %p, %Z", "%I:%M %p"],
889         "american" : ["%I:%M:%S %p %Z", "%I:%M %p"],
890         "amharic" : ["%I:%M:%S %p %Z", "%I:%M %p"],
891         "ancientgreek" : ["%H:%M:%S %Z", "%H:%M:%S"],
892         "arabic_arabi" : ["%I:%M:%S %p %Z", "%I:%M %p"],
893         "arabic_arabtex" : ["%I:%M:%S %p %Z", "%I:%M %p"],
894         "armenian" : ["%H:%M:%S %Z", "%H:%M"],
895         "asturian" : ["%H:%M:%S %Z", "%H:%M"],
896         "australian" : ["%I:%M:%S %p %Z", "%I:%M %p"],
897         "austrian" : ["%H:%M:%S %Z", "%H:%M"],
898         "bahasa" : ["%H.%M.%S %Z", "%H.%M"],
899         "bahasam" : ["%I:%M:%S %p %Z", "%I:%M %p"],
900         "basque" : ["%H:%M:%S (%Z)", "%H:%M"],
901         "belarusian" : ["%H:%M:%S, %Z", "%H:%M"],
902         "bosnian" : ["%H:%M:%S %Z", "%H:%M"],
903         "brazilian" : ["%H:%M:%S %Z", "%H:%M"],
904         "breton" : ["%H:%M:%S %Z", "%H:%M"],
905         "british" : ["%H:%M:%S %Z", "%H:%M"],
906         "bulgarian" : ["%H:%M:%S %Z", "%H:%M"],
907         "canadian" : ["%I:%M:%S %p %Z", "%I:%M %p"],
908         "canadien" : ["%H:%M:%S %Z", "%H h %M"],
909         "catalan" : ["%H:%M:%S %Z", "%H:%M"],
910         "chinese-simplified" : ["%Z %p%I:%M:%S", "%p%I:%M"],
911         "chinese-traditional" : ["%p%I:%M:%S [%Z]", "%p%I:%M"],
912         "coptic" : ["%H:%M:%S %Z", "%H:%M:%S"],
913         "croatian" : ["%H:%M:%S (%Z)", "%H:%M"],
914         "czech" : ["%H:%M:%S %Z", "%H:%M"],
915         "danish" : ["%H.%M.%S %Z", "%H.%M"],
916         "divehi" : ["%H:%M:%S %Z", "%H:%M"],
917         "dutch" : ["%H:%M:%S %Z", "%H:%M"],
918         "english" : ["%I:%M:%S %p %Z", "%I:%M %p"],
919         "esperanto" : ["%H:%M:%S %Z", "%H:%M:%S"],
920         "estonian" : ["%H:%M:%S %Z", "%H:%M"],
921         "farsi" : ["%H:%M:%S (%Z)", "%H:%M"],
922         "finnish" : ["%H.%M.%S %Z", "%H.%M"],
923         "french" : ["%H:%M:%S %Z", "%H:%M"],
924         "friulan" : ["%H:%M:%S %Z", "%H:%M"],
925         "galician" : ["%H:%M:%S %Z", "%H:%M"],
926         "georgian" : ["%H:%M:%S %Z", "%H:%M"],
927         "german" : ["%H:%M:%S %Z", "%H:%M"],
928         "german-ch" : ["%H:%M:%S %Z", "%H:%M"],
929         "german-ch-old" : ["%H:%M:%S %Z", "%H:%M"],
930         "greek" : ["%I:%M:%S %p %Z", "%I:%M %p"],
931         "hebrew" : ["%H:%M:%S %Z", "%H:%M"],
932         "hindi" : ["%I:%M:%S %p %Z", "%I:%M %p"],
933         "icelandic" : ["%H:%M:%S %Z", "%H:%M"],
934         "interlingua" : ["%H:%M:%S %Z", "%H:%M"],
935         "irish" : ["%H:%M:%S %Z", "%H:%M"],
936         "italian" : ["%H:%M:%S %Z", "%H:%M"],
937         "japanese" : ["%H時%M分%S秒 %Z", "%H:%M"],
938         "japanese-cjk" : ["%H時%M分%S秒 %Z", "%H:%M"],
939         "kannada" : ["%I:%M:%S %p %Z", "%I:%M %p"],
940         "kazakh" : ["%H:%M:%S %Z", "%H:%M"],
941         "khmer" : ["%I:%M:%S %p %Z", "%I:%M %p"],
942         "korean" : ["%p %I시%M분 %S초 %Z", "%p %I:%M"],
943         "kurmanji" : ["%H:%M:%S %Z", "%H:%M:%S"],
944         "lao" : ["%H ໂມງ%M ນາທີ  %S ວິນາທີ %Z", "%H:%M"],
945         "latin" : ["%H:%M:%S %Z", "%H:%M:%S"],
946         "latvian" : ["%H:%M:%S %Z", "%H:%M"],
947         "lithuanian" : ["%H:%M:%S %Z", "%H:%M"],
948         "lowersorbian" : ["%H:%M:%S %Z", "%H:%M"],
949         "macedonian" : ["%H:%M:%S %Z", "%H:%M"],
950         "magyar" : ["%H:%M:%S %Z", "%H:%M"],
951         "marathi" : ["%I:%M:%S %p %Z", "%I:%M %p"],
952         "mongolian" : ["%H:%M:%S %Z", "%H:%M"],
953         "naustrian" : ["%H:%M:%S %Z", "%H:%M"],
954         "newzealand" : ["%I:%M:%S %p %Z", "%I:%M %p"],
955         "ngerman" : ["%H:%M:%S %Z", "%H:%M"],
956         "norsk" : ["%H:%M:%S %Z", "%H:%M"],
957         "nynorsk" : ["kl. %H:%M:%S %Z", "%H:%M"],
958         "occitan" : ["%H:%M:%S %Z", "%H:%M"],
959         "piedmontese" : ["%H:%M:%S %Z", "%H:%M:%S"],
960         "polish" : ["%H:%M:%S %Z", "%H:%M"],
961         "polutonikogreek" : ["%I:%M:%S %p %Z", "%I:%M %p"],
962         "portuguese" : ["%H:%M:%S %Z", "%H:%M"],
963         "romanian" : ["%H:%M:%S %Z", "%H:%M"],
964         "romansh" : ["%H:%M:%S %Z", "%H:%M"],
965         "russian" : ["%H:%M:%S %Z", "%H:%M"],
966         "samin" : ["%H:%M:%S %Z", "%H:%M"],
967         "sanskrit" : ["%H:%M:%S %Z", "%H:%M"],
968         "scottish" : ["%H:%M:%S %Z", "%H:%M"],
969         "serbian" : ["%H:%M:%S %Z", "%H:%M"],
970         "serbian-latin" : ["%H:%M:%S %Z", "%H:%M"],
971         "slovak" : ["%H:%M:%S %Z", "%H:%M"],
972         "slovene" : ["%H:%M:%S %Z", "%H:%M"],
973         "spanish" : ["%H:%M:%S (%Z)", "%H:%M"],
974         "spanish-mexico" : ["%H:%M:%S %Z", "%H:%M"],
975         "swedish" : ["kl. %H:%M:%S %Z", "%H:%M"],
976         "syriac" : ["%H:%M:%S %Z", "%H:%M"],
977         "tamil" : ["%p %I:%M:%S %Z", "%p %I:%M"],
978         "telugu" : ["%I:%M:%S %p %Z", "%I:%M %p"],
979         "thai" : ["%H นาฬิกา %M นาที  %S วินาที %Z", "%H:%M"],
980         "tibetan" : ["%I:%M:%S %p %Z", "%I:%M %p"],
981         "turkish" : ["%H:%M:%S %Z", "%H:%M"],
982         "turkmen" : ["%H:%M:%S %Z", "%H:%M"],
983         "ukrainian" : ["%H:%M:%S %Z", "%H:%M"],
984         "uppersorbian" : ["%H:%M:%S %Z", "%H:%M hodź."],
985         "urdu" : ["%I:%M:%S %p %Z", "%I:%M %p"],
986         "vietnamese" : ["%H:%M:%S %Z", "%H:%M"],
987         "welsh" : ["%H:%M:%S %Z", "%H:%M"]
988     }
989
990     types = ["time", "fixtime", "modtime" ]
991     i = 0
992     i = find_token(document.header, "\\language", 0)
993     if i == -1:
994         # this should not happen
995         document.warning("Malformed LyX document! No \\language header found!")
996         return
997     lang = get_value(document.header, "\\language", i)
998
999     i = 0
1000     while True:
1001         i = find_token(document.body, "\\begin_inset Info", i)
1002         if i == -1:
1003             return
1004         j = find_end_of_inset(document.body, i + 1)
1005         if j == -1:
1006             document.warning("Malformed LyX document: Could not find end of Info inset.")
1007             i = i + 1
1008             continue
1009         tp = find_token(document.body, 'type', i, j)
1010         tpv = get_quoted_value(document.body, "type", tp)
1011         if tpv not in types:
1012             i = i + 1
1013             continue
1014         arg = find_token(document.body, 'arg', i, j)
1015         argv = get_quoted_value(document.body, "arg", arg)
1016         isotime = ""
1017         dtme = datetime.now()
1018         tme = dtme.time()
1019         if tpv == "fixtime":
1020             timecomps = argv.split('@')
1021             if len(timecomps) > 1:
1022                 argv = timecomps[0]
1023                 isotime = timecomps[1]
1024                 m = re.search('(\d\d):(\d\d):(\d\d)', isotime)
1025                 if m:
1026                     tme = time(int(m.group(1)), int(m.group(2)), int(m.group(3)))
1027                 else:
1028                     m = re.search('(\d\d):(\d\d)', isotime)
1029                     if m:
1030                         tme = time(int(m.group(1)), int(m.group(2)))
1031 # FIXME if we had the path to the original document (not the one in the tmp dir),
1032 #        we could use the mtime.
1033 #        elif tpv == "moddate":
1034 #            dte = date.fromtimestamp(os.path.getmtime(document.dir))
1035         result = ""
1036         if argv == "ISO":
1037             result = tme.isoformat()
1038         elif argv == "long":
1039             result = tme.strftime(timeformats[lang][0])
1040         elif argv == "short":
1041             result = tme.strftime(timeformats[lang][1])
1042         else:
1043             fmt = argv.replace("HH", "%H").replace("H", "%H").replace("hh", "%I").replace("h", "%I")
1044             fmt = fmt.replace("mm", "%M").replace("m", "%M").replace("ss", "%S").replace("s", "%S")
1045             fmt = fmt.replace("zzz", "%f").replace("z", "%f").replace("t", "%Z")
1046             fmt = fmt.replace("AP", "%p").replace("ap", "%p").replace("A", "%p").replace("a", "%p")
1047             fmt = fmt.replace("'", "")
1048             result = dte.strftime(fmt)
1049         document.body[i : j+1] = result
1050         i = i + 1
1051
1052
1053 def revert_namenoextinfo(document):
1054     " Merge buffer Info inset type name-noext to name. "
1055
1056     i = 0
1057     while True:
1058         i = find_token(document.body, "\\begin_inset Info", i)
1059         if i == -1:
1060             return
1061         j = find_end_of_inset(document.body, i + 1)
1062         if j == -1:
1063             document.warning("Malformed LyX document: Could not find end of Info inset.")
1064             i = i + 1
1065             continue
1066         tp = find_token(document.body, 'type', i, j)
1067         tpv = get_quoted_value(document.body, "type", tp)
1068         if tpv != "buffer":
1069             i = i + 1
1070             continue
1071         arg = find_token(document.body, 'arg', i, j)
1072         argv = get_quoted_value(document.body, "arg", arg)
1073         if argv != "name-noext":
1074             i = i + 1
1075             continue
1076         document.body[arg] = "arg \"name\""
1077         i = i + 1
1078
1079
1080 ##
1081 # Conversion hub
1082 #
1083
1084 supported_versions = ["2.4.0", "2.4"]
1085 convert = [
1086            [545, [convert_lst_literalparam]],
1087            [546, []],
1088            [547, []],
1089            [548, []],
1090            [549, []],
1091            [550, [convert_fontenc]],
1092            [551, []],
1093            [552, []],
1094            [553, []],
1095            [554, []],
1096            [555, []],
1097            [556, []],
1098            [557, [convert_vcsinfo]],
1099            [558, [removeFrontMatterStyles]],
1100            [559, []],
1101            [560, []],
1102            [561, []]
1103           ]
1104
1105 revert =  [
1106            [560, [revert_dejavu]],
1107            [559, [revert_timeinfo, revert_namenoextinfo]],
1108            [558, [revert_dateinfo]],
1109            [557, [addFrontMatterStyles]],
1110            [556, [revert_vcsinfo]],
1111            [555, [revert_bibencoding]],
1112            [554, [revert_vcolumns]],
1113            [553, [revert_stretchcolumn]],
1114            [552, [revert_tuftecite]],
1115            [551, [revert_floatpclass, revert_floatalignment]],
1116            [550, [revert_nospellcheck]],
1117            [549, [revert_fontenc]],
1118            [548, []],# dummy format change
1119            [547, [revert_lscape]],
1120            [546, [revert_xcharter]],
1121            [545, [revert_paratype]],
1122            [544, [revert_lst_literalparam]]
1123           ]
1124
1125
1126 if __name__ == "__main__":
1127     pass