1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2006 José Matos <jamatos@lyx.org>
4 # Copyright (C) 2004-2006 Georg Baum <Georg.Baum@post.rwth-aachen.de>
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 """ Convert files to the file format generated by lyx 1.5"""
23 from parser_tools import find_token, find_token_backwards, find_token_exact, find_tokens, find_end_of, get_value
24 from LyX import get_encoding
27 ####################################################################
28 # Private helper functions
30 def find_end_of_inset(lines, i):
31 " Find end of inset, where lines[i] is included."
32 return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
34 def find_end_of_layout(lines, i):
35 " Find end of layout, where lines[i] is included."
36 return find_end_of(lines, i, "\\begin_layout", "\\end_layout")
38 # End of helper functions
39 ####################################################################
43 # Notes: Framed/Shaded
46 def revert_framed(document):
47 "Revert framed notes. "
50 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
54 document.body[i] = "\\begin_inset Note"
62 roman_fonts = {'default' : 'default', 'ae' : 'ae',
63 'times' : 'times', 'palatino' : 'palatino',
64 'helvet' : 'default', 'avant' : 'default',
65 'newcent' : 'newcent', 'bookman' : 'bookman',
67 sans_fonts = {'default' : 'default', 'ae' : 'default',
68 'times' : 'default', 'palatino' : 'default',
69 'helvet' : 'helvet', 'avant' : 'avant',
70 'newcent' : 'default', 'bookman' : 'default',
72 typewriter_fonts = {'default' : 'default', 'ae' : 'default',
73 'times' : 'default', 'palatino' : 'default',
74 'helvet' : 'default', 'avant' : 'default',
75 'newcent' : 'default', 'bookman' : 'default',
76 'pslatex' : 'courier'}
78 def convert_font_settings(document):
79 " Convert font settings. "
81 i = find_token_exact(document.header, "\\fontscheme", i)
83 document.warning("Malformed LyX document: Missing `\\fontscheme'.")
85 font_scheme = get_value(document.header, "\\fontscheme", i, i + 1)
87 document.warning("Malformed LyX document: Empty `\\fontscheme'.")
88 font_scheme = 'default'
89 if not font_scheme in roman_fonts.keys():
90 document.warning("Malformed LyX document: Unknown `\\fontscheme' `%s'." % font_scheme)
91 font_scheme = 'default'
92 document.header[i:i+1] = ['\\font_roman %s' % roman_fonts[font_scheme],
93 '\\font_sans %s' % sans_fonts[font_scheme],
94 '\\font_typewriter %s' % typewriter_fonts[font_scheme],
95 '\\font_default_family default',
98 '\\font_sf_scale 100',
99 '\\font_tt_scale 100']
102 def revert_font_settings(document):
103 " Revert font settings. "
106 fonts = {'roman' : 'default', 'sans' : 'default', 'typewriter' : 'default'}
107 for family in 'roman', 'sans', 'typewriter':
108 name = '\\font_%s' % family
109 i = find_token_exact(document.header, name, i)
111 document.warning("Malformed LyX document: Missing `%s'." % name)
114 if (insert_line < 0):
116 fonts[family] = get_value(document.header, name, i, i + 1)
117 del document.header[i]
118 i = find_token_exact(document.header, '\\font_default_family', i)
120 document.warning("Malformed LyX document: Missing `\\font_default_family'.")
121 font_default_family = 'default'
123 font_default_family = get_value(document.header, "\\font_default_family", i, i + 1)
124 del document.header[i]
125 i = find_token_exact(document.header, '\\font_sc', i)
127 document.warning("Malformed LyX document: Missing `\\font_sc'.")
130 font_sc = get_value(document.header, '\\font_sc', i, i + 1)
131 del document.header[i]
132 if font_sc != 'false':
133 document.warning("Conversion of '\\font_sc' not yet implemented.")
134 i = find_token_exact(document.header, '\\font_osf', i)
136 document.warning("Malformed LyX document: Missing `\\font_osf'.")
139 font_osf = get_value(document.header, '\\font_osf', i, i + 1)
140 del document.header[i]
141 i = find_token_exact(document.header, '\\font_sf_scale', i)
143 document.warning("Malformed LyX document: Missing `\\font_sf_scale'.")
144 font_sf_scale = '100'
146 font_sf_scale = get_value(document.header, '\\font_sf_scale', i, i + 1)
147 del document.header[i]
148 if font_sf_scale != '100':
149 document.warning("Conversion of '\\font_sf_scale' not yet implemented.")
150 i = find_token_exact(document.header, '\\font_tt_scale', i)
152 document.warning("Malformed LyX document: Missing `\\font_tt_scale'.")
153 font_tt_scale = '100'
155 font_tt_scale = get_value(document.header, '\\font_tt_scale', i, i + 1)
156 del document.header[i]
157 if font_tt_scale != '100':
158 document.warning("Conversion of '\\font_tt_scale' not yet implemented.")
159 for font_scheme in roman_fonts.keys():
160 if (roman_fonts[font_scheme] == fonts['roman'] and
161 sans_fonts[font_scheme] == fonts['sans'] and
162 typewriter_fonts[font_scheme] == fonts['typewriter']):
163 document.header.insert(insert_line, '\\fontscheme %s' % font_scheme)
164 if font_default_family != 'default':
165 document.preamble.append('\\renewcommand{\\familydefault}{\\%s}' % font_default_family)
166 if font_osf == 'true':
167 document.warning("Ignoring `\\font_osf = true'")
169 font_scheme = 'default'
170 document.header.insert(insert_line, '\\fontscheme %s' % font_scheme)
171 if fonts['roman'] == 'cmr':
172 document.preamble.append('\\renewcommand{\\rmdefault}{cmr}')
173 if font_osf == 'true':
174 document.preamble.append('\\usepackage{eco}')
176 for font in 'lmodern', 'charter', 'utopia', 'beraserif', 'ccfonts', 'chancery':
177 if fonts['roman'] == font:
178 document.preamble.append('\\usepackage{%s}' % font)
179 for font in 'cmss', 'lmss', 'cmbr':
180 if fonts['sans'] == font:
181 document.preamble.append('\\renewcommand{\\sfdefault}{%s}' % font)
182 for font in 'berasans':
183 if fonts['sans'] == font:
184 document.preamble.append('\\usepackage{%s}' % font)
185 for font in 'cmtt', 'lmtt', 'cmtl':
186 if fonts['typewriter'] == font:
187 document.preamble.append('\\renewcommand{\\ttdefault}{%s}' % font)
188 for font in 'courier', 'beramono', 'luximono':
189 if fonts['typewriter'] == font:
190 document.preamble.append('\\usepackage{%s}' % font)
191 if font_default_family != 'default':
192 document.preamble.append('\\renewcommand{\\familydefault}{\\%s}' % font_default_family)
193 if font_osf == 'true':
194 document.warning("Ignoring `\\font_osf = true'")
197 def revert_booktabs(document):
198 " We remove the booktabs flag or everything else will become a mess. "
199 re_row = re.compile(r'^<row.*space="[^"]+".*>$')
200 re_tspace = re.compile(r'\s+topspace="[^"]+"')
201 re_bspace = re.compile(r'\s+bottomspace="[^"]+"')
202 re_ispace = re.compile(r'\s+interlinespace="[^"]+"')
205 i = find_token(document.body, "\\begin_inset Tabular", i)
208 j = find_end_of_inset(document.body, i + 1)
210 document.warning("Malformed LyX document: Could not find end of tabular.")
212 for k in range(i, j):
213 if re.search('^<features.* booktabs="true".*>$', document.body[k]):
214 document.warning("Converting 'booktabs' table to normal table.")
215 document.body[k] = document.body[k].replace(' booktabs="true"', '')
216 if re.search(re_row, document.body[k]):
217 document.warning("Removing extra row space.")
218 document.body[k] = re_tspace.sub('', document.body[k])
219 document.body[k] = re_bspace.sub('', document.body[k])
220 document.body[k] = re_ispace.sub('', document.body[k])
224 def convert_multiencoding(document, forward):
225 """ Fix files with multiple encodings.
226 Files with an inputencoding of "auto" or "default" and multiple languages
227 where at least two languages have different default encodings are encoded
228 in multiple encodings for file formats < 249. These files are incorrectly
229 read and written (as if the whole file was in the encoding of the main
233 - converts from fake unicode values to true unicode if forward is true, and
234 - converts from true unicode values to fake unicode if forward is false.
235 document.encoding must be set to the old value (format 248) in both cases.
237 We do this here and not in LyX.py because it is far easier to do the
238 necessary parsing in modern formats than in ancient ones.
240 encoding_stack = [document.encoding]
241 lang_re = re.compile(r"^\\lang\s(\S+)")
242 if document.inputencoding == "auto" or document.inputencoding == "default":
243 for i in range(len(document.body)):
244 result = lang_re.match(document.body[i])
246 language = result.group(1)
247 if language == "default":
248 document.warning("Resetting encoding from %s to %s." % (encoding_stack[-1], document.encoding))
249 encoding_stack[-1] = document.encoding
251 from lyx2lyx_lang import lang
252 document.warning("Setting encoding from %s to %s." % (encoding_stack[-1], lang[language][3]))
253 encoding_stack[-1] = lang[language][3]
254 elif find_token(document.body, "\\begin_layout", i, i + 1) == i:
255 document.warning("Adding nested encoding %s." % encoding_stack[-1])
256 encoding_stack.append(encoding_stack[-1])
257 elif find_token(document.body, "\\end_layout", i, i + 1) == i:
258 document.warning("Removing nested encoding %s." % encoding_stack[-1])
259 del encoding_stack[-1]
260 if encoding_stack[-1] != document.encoding:
262 # This line has been incorrectly interpreted as if it was
263 # encoded in 'encoding'.
264 # Convert back to the 8bit string that was in the file.
265 orig = document.body[i].encode(document.encoding)
266 # Convert the 8bit string that was in the file to unicode
267 # with the correct encoding.
268 document.body[i] = orig.decode(encoding_stack[-1])
270 # Convert unicode to the 8bit string that will be written
271 # to the file with the correct encoding.
272 orig = document.body[i].encode(encoding_stack[-1])
273 # Convert the 8bit string that will be written to the
274 # file to fake unicode with the encoding that will later
275 # be used when writing to the file.
276 document.body[i] = orig.decode(document.encoding)
279 def convert_utf8(document):
280 " Set document encoding to UTF-8. "
281 convert_multiencoding(document, True)
282 document.encoding = "utf8"
285 def revert_utf8(document):
286 " Set document encoding to the value corresponding to inputencoding. "
287 i = find_token(document.header, "\\inputencoding", 0)
289 document.header.append("\\inputencoding auto")
290 elif get_value(document.header, "\\inputencoding", i) == "utf8":
291 document.header[i] = "\\inputencoding auto"
292 document.inputencoding = get_value(document.header, "\\inputencoding", 0)
293 document.encoding = get_encoding(document.language, document.inputencoding, 248)
294 convert_multiencoding(document, False)
297 def revert_cs_label(document):
298 " Remove status flag of charstyle label. "
301 i = find_token(document.body, "\\begin_inset CharStyle", i)
304 # Seach for a line starting 'show_label'
305 # If it is not there, break with a warning message
308 if (document.body[i][:10] == "show_label"):
311 elif (document.body[i][:13] == "\\begin_layout"):
312 document.warning("Malformed LyX document: Missing 'show_label'.")
319 def convert_bibitem(document):
321 \bibitem [option]{argument}
325 \begin_inset LatexCommand bibitem
331 This must be called after convert_commandparams.
333 regex = re.compile(r'\S+\s*(\[[^\[\{]*\])?(\{[^}]*\})')
336 i = find_token(document.body, "\\bibitem", i)
339 match = re.match(regex, document.body[i])
340 option = match.group(1)
341 argument = match.group(2)
342 lines = ['\\begin_inset LatexCommand bibitem']
344 lines.append('label "%s"' % option[1:-1].replace('"', '\\"'))
345 lines.append('key "%s"' % argument[1:-1].replace('"', '\\"'))
347 lines.append('\\end_inset')
348 document.body[i:i+1] = lines
352 commandparams_info = {
353 # command : [option1, option2, argument]
354 "bibitem" : ["label", "", "key"],
355 "bibtex" : ["options", "btprint", "bibfiles"],
356 "cite" : ["after", "before", "key"],
357 "citet" : ["after", "before", "key"],
358 "citep" : ["after", "before", "key"],
359 "citealt" : ["after", "before", "key"],
360 "citealp" : ["after", "before", "key"],
361 "citeauthor" : ["after", "before", "key"],
362 "citeyear" : ["after", "before", "key"],
363 "citeyearpar" : ["after", "before", "key"],
364 "citet*" : ["after", "before", "key"],
365 "citep*" : ["after", "before", "key"],
366 "citealt*" : ["after", "before", "key"],
367 "citealp*" : ["after", "before", "key"],
368 "citeauthor*" : ["after", "before", "key"],
369 "Citet" : ["after", "before", "key"],
370 "Citep" : ["after", "before", "key"],
371 "Citealt" : ["after", "before", "key"],
372 "Citealp" : ["after", "before", "key"],
373 "Citeauthor" : ["after", "before", "key"],
374 "Citet*" : ["after", "before", "key"],
375 "Citep*" : ["after", "before", "key"],
376 "Citealt*" : ["after", "before", "key"],
377 "Citealp*" : ["after", "before", "key"],
378 "Citeauthor*" : ["after", "before", "key"],
379 "citefield" : ["after", "before", "key"],
380 "citetitle" : ["after", "before", "key"],
381 "cite*" : ["after", "before", "key"],
382 "hfill" : ["", "", ""],
383 "index" : ["", "", "name"],
384 "printindex" : ["", "", "name"],
385 "label" : ["", "", "name"],
386 "eqref" : ["name", "", "reference"],
387 "pageref" : ["name", "", "reference"],
388 "prettyref" : ["name", "", "reference"],
389 "ref" : ["name", "", "reference"],
390 "vpageref" : ["name", "", "reference"],
391 "vref" : ["name", "", "reference"],
392 "tableofcontents" : ["", "", "type"],
393 "htmlurl" : ["name", "", "target"],
394 "url" : ["name", "", "target"]}
397 def convert_commandparams(document):
400 \begin_inset LatexCommand \cmdname[opt1][opt2]{arg}
405 \begin_inset LatexCommand cmdname
411 name1, name2 and name3 can be different for each command.
413 # \begin_inset LatexCommand bibitem was not the official version (see
414 # convert_bibitem()), but could be read in, so we convert it here, too.
418 i = find_token(document.body, "\\begin_inset LatexCommand", i)
421 command = document.body[i][26:].strip()
423 document.warning("Malformed LyX document: Missing LatexCommand name.")
427 # The following parser is taken from the original InsetCommandParams::scanCommand
433 # Used to handle things like \command[foo[bar]]{foo{bar}}
437 if ((state == "CMDNAME" and c == ' ') or
438 (state == "CMDNAME" and c == '[') or
439 (state == "CMDNAME" and c == '{')):
441 if ((state == "OPTION" and c == ']') or
442 (state == "SECOPTION" and c == ']') or
443 (state == "CONTENT" and c == '}')):
447 nestdepth = nestdepth - 1
448 if ((state == "OPTION" and c == '[') or
449 (state == "SECOPTION" and c == '[') or
450 (state == "CONTENT" and c == '{')):
451 nestdepth = nestdepth + 1
452 if state == "CMDNAME":
454 elif state == "OPTION":
456 elif state == "SECOPTION":
458 elif state == "CONTENT":
463 elif c == '[' and b != ']':
465 nestdepth = 0 # Just to be sure
466 elif c == '[' and b == ']':
468 nestdepth = 0 # Just to be sure
471 nestdepth = 0 # Just to be sure
474 # Now we have parsed the command, output the parameters
475 lines = ["\\begin_inset LatexCommand %s" % name]
477 if commandparams_info[name][0] == "":
478 document.warning("Ignoring invalid option `%s' of command `%s'." % (option1, name))
480 lines.append('%s "%s"' % (commandparams_info[name][0], option1.replace('"', '\\"')))
482 if commandparams_info[name][1] == "":
483 document.warning("Ignoring invalid second option `%s' of command `%s'." % (option2, name))
485 lines.append('%s "%s"' % (commandparams_info[name][1], option2.replace('"', '\\"')))
487 if commandparams_info[name][2] == "":
488 document.warning("Ignoring invalid argument `%s' of command `%s'." % (argument, name))
490 lines.append('%s "%s"' % (commandparams_info[name][2], argument.replace('"', '\\"')))
491 document.body[i:i+1] = lines
495 def revert_commandparams(document):
496 regex = re.compile(r'(\S+)\s+(.+)')
499 i = find_token(document.body, "\\begin_inset LatexCommand", i)
502 name = document.body[i].split()[2]
503 j = find_end_of_inset(document.body, i + 1)
508 for k in range(i + 1, j):
509 match = re.match(regex, document.body[k])
511 pname = match.group(1)
512 pvalue = match.group(2)
513 if pname == "preview":
514 preview_line = document.body[k]
515 elif (commandparams_info[name][0] != "" and
516 pname == commandparams_info[name][0]):
517 option1 = pvalue.strip('"').replace('\\"', '"')
518 elif (commandparams_info[name][1] != "" and
519 pname == commandparams_info[name][1]):
520 option2 = pvalue.strip('"').replace('\\"', '"')
521 elif (commandparams_info[name][2] != "" and
522 pname == commandparams_info[name][2]):
523 argument = pvalue.strip('"').replace('\\"', '"')
524 elif document.body[k].strip() != "":
525 document.warning("Ignoring unknown contents `%s' in command inset %s." % (document.body[k], name))
526 if name == "bibitem":
528 lines = ["\\bibitem {%s}" % argument]
530 lines = ["\\bibitem [%s]{%s}" % (option1, argument)]
534 lines = ["\\begin_inset LatexCommand \\%s{%s}" % (name, argument)]
536 lines = ["\\begin_inset LatexCommand \\%s[][%s]{%s}" % (name, option2, argument)]
539 lines = ["\\begin_inset LatexCommand \\%s[%s]{%s}" % (name, option1, argument)]
541 lines = ["\\begin_inset LatexCommand \\%s[%s][%s]{%s}" % (name, option1, option2, argument)]
542 if name != "bibitem":
543 if preview_line != "":
544 lines.append(preview_line)
546 lines.append('\\end_inset')
547 document.body[i:j+1] = lines
551 def revert_nomenclature(document):
552 " Convert nomenclature entry to ERT. "
553 regex = re.compile(r'(\S+)\s+(.+)')
557 i = find_token(document.body, "\\begin_inset LatexCommand nomenclature", i)
561 j = find_end_of_inset(document.body, i + 1)
566 for k in range(i + 1, j):
567 match = re.match(regex, document.body[k])
569 name = match.group(1)
570 value = match.group(2)
571 if name == "preview":
572 preview_line = document.body[k]
573 elif name == "symbol":
574 symbol = value.strip('"').replace('\\"', '"')
575 elif name == "description":
576 description = value.strip('"').replace('\\"', '"')
577 elif name == "prefix":
578 prefix = value.strip('"').replace('\\"', '"')
579 elif document.body[k].strip() != "":
580 document.warning("Ignoring unknown contents `%s' in nomenclature inset." % document.body[k])
582 command = 'nomenclature{%s}{%s}' % (symbol, description)
584 command = 'nomenclature[%s]{%s}{%s}' % (prefix, symbol, description)
585 document.body[i:j+1] = ['\\begin_inset ERT',
588 '\\begin_layout %s' % document.default_layout,
597 if use_nomencl and find_token(document.preamble, '\\usepackage{nomencl}[2005/09/22]', 0) == -1:
598 document.preamble.append('\\usepackage{nomencl}[2005/09/22]')
599 document.preamble.append('\\makenomenclature')
602 def revert_printnomenclature(document):
603 " Convert printnomenclature to ERT. "
604 regex = re.compile(r'(\S+)\s+(.+)')
608 i = find_token(document.body, "\\begin_inset LatexCommand printnomenclature", i)
612 j = find_end_of_inset(document.body, i + 1)
615 for k in range(i + 1, j):
616 match = re.match(regex, document.body[k])
618 name = match.group(1)
619 value = match.group(2)
620 if name == "preview":
621 preview_line = document.body[k]
622 elif name == "labelwidth":
623 labelwidth = value.strip('"').replace('\\"', '"')
624 elif document.body[k].strip() != "":
625 document.warning("Ignoring unknown contents `%s' in printnomenclature inset." % document.body[k])
627 command = 'nomenclature{}'
629 command = 'nomenclature[%s]' % labelwidth
630 document.body[i:j+1] = ['\\begin_inset ERT',
633 '\\begin_layout %s' % document.default_layout,
642 if use_nomencl and find_token(document.preamble, '\\usepackage{nomencl}[2005/09/22]', 0) == -1:
643 document.preamble.append('\\usepackage{nomencl}[2005/09/22]')
644 document.preamble.append('\\makenomenclature')
647 def convert_esint(document):
648 " Add \\use_esint setting to header. "
649 i = find_token(document.header, "\\cite_engine", 0)
651 document.warning("Malformed LyX document: Missing `\\cite_engine'.")
653 # 0 is off, 1 is auto, 2 is on.
654 document.header.insert(i, '\\use_esint 0')
657 def revert_esint(document):
658 " Remove \\use_esint setting from header. "
659 i = find_token(document.header, "\\use_esint", 0)
661 document.warning("Malformed LyX document: Missing `\\use_esint'.")
663 use_esint = document.header[i].split()[1]
664 del document.header[i]
665 # 0 is off, 1 is auto, 2 is on.
667 document.preamble.append('\\usepackage{esint}')
670 def revert_clearpage(document):
674 i = find_token(document.body, "\\clearpage", i)
677 document.body[i:i+1] = ['\\begin_inset ERT',
680 '\\begin_layout %s' % document.default_layout,
691 def revert_cleardoublepage(document):
692 " cleardoublepage -> ERT "
695 i = find_token(document.body, "\\cleardoublepage", i)
698 document.body[i:i+1] = ['\\begin_inset ERT',
701 '\\begin_layout %s' % document.default_layout,
712 def convert_lyxline(document):
713 " remove fontsize commands for \lyxline "
714 # The problematic is: The old \lyxline definition doesn't handle the fontsize
715 # to change the line thickness. The new definiton does this so that imported
716 # \lyxlines would have a different line thickness. The eventual fontsize command
717 # before \lyxline is therefore removed to get the same output.
718 fontsizes = ["tiny", "scriptsize", "footnotesize", "small", "normalsize",
719 "large", "Large", "LARGE", "huge", "Huge"]
720 for n in range(0, len(fontsizes)-1):
724 i = find_token(document.body, "\\size " + fontsizes[n], i)
725 k = find_token(document.body, "\\lyxline",i)
726 # the corresponding fontsize command is always 2 lines before the \lyxline
727 if (i != -1 and k == i+2):
728 document.body[i:i+1] = []
734 def revert_encodings(document):
735 " Set new encodings to auto. "
736 encodings = ["8859-6", "8859-8", "cp437", "cp437de", "cp850", "cp852",
737 "cp855", "cp858", "cp862", "cp865", "cp866", "cp1250",
738 "cp1252", "cp1256", "cp1257", "latin10", "pt254", "tis620-0"]
739 i = find_token(document.header, "\\inputencoding", 0)
741 document.header.append("\\inputencoding auto")
743 inputenc = get_value(document.header, "\\inputencoding", i)
744 if inputenc in encodings:
745 document.header[i] = "\\inputencoding auto"
746 document.inputencoding = get_value(document.header, "\\inputencoding", 0)
749 def convert_caption(document):
750 " Convert caption layouts to caption insets. "
753 i = find_token(document.body, "\\begin_layout Caption", i)
756 j = find_end_of_layout(document.body, i)
758 document.warning("Malformed LyX document: Missing `\\end_layout'.")
761 document.body[j:j] = ["\\end_layout", "", "\\end_inset", "", ""]
762 document.body[i:i+1] = ["\\begin_layout %s" % document.default_layout,
763 "\\begin_inset Caption", "",
764 "\\begin_layout %s" % document.default_layout]
768 def revert_caption(document):
769 " Convert caption insets to caption layouts. "
770 " This assumes that the text class has a caption style. "
773 i = find_token(document.body, "\\begin_inset Caption", i)
777 # We either need to delete the previous \begin_layout line, or we
778 # need to end the previous layout if this inset is not in the first
779 # position of the paragraph.
780 layout_before = find_token_backwards(document.body, "\\begin_layout", i)
781 if layout_before == -1:
782 document.warning("Malformed LyX document: Missing `\\begin_layout'.")
784 layout_line = document.body[layout_before]
785 del_layout_before = True
786 l = layout_before + 1
788 if document.body[l] != "":
789 del_layout_before = False
792 if del_layout_before:
793 del document.body[layout_before:i]
796 document.body[i:i] = ["\\end_layout", ""]
799 # Find start of layout in the inset and end of inset
800 j = find_token(document.body, "\\begin_layout", i)
802 document.warning("Malformed LyX document: Missing `\\begin_layout'.")
804 k = find_end_of_inset(document.body, i)
806 document.warning("Malformed LyX document: Missing `\\end_inset'.")
809 # We either need to delete the following \end_layout line, or we need
810 # to restart the old layout if this inset is not at the paragraph end.
811 layout_after = find_token(document.body, "\\end_layout", k)
812 if layout_after == -1:
813 document.warning("Malformed LyX document: Missing `\\end_layout'.")
815 del_layout_after = True
817 while l < layout_after:
818 if document.body[l] != "":
819 del_layout_after = False
823 del document.body[k+1:layout_after+1]
825 document.body[k+1:k+1] = [layout_line, ""]
827 # delete \begin_layout and \end_inset and replace \begin_inset with
828 # "\begin_layout Caption". This works because we can only have one
829 # paragraph in the caption inset: The old \end_layout will be recycled.
831 if document.body[k] == "":
834 if document.body[j] == "":
836 document.body[i] = "\\begin_layout Caption"
837 if document.body[i+1] == "":
838 del document.body[i+1]
846 supported_versions = ["1.5.0","1.5"]
847 convert = [[246, []],
848 [247, [convert_font_settings]],
850 [249, [convert_utf8]],
853 [252, [convert_commandparams, convert_bibitem]],
855 [254, [convert_esint]],
858 [257, [convert_caption, convert_lyxline]]]
860 revert = [[256, [revert_caption]],
861 [255, [revert_encodings]],
862 [254, [revert_clearpage, revert_cleardoublepage]],
863 [253, [revert_esint]],
864 [252, [revert_nomenclature, revert_printnomenclature]],
865 [251, [revert_commandparams]],
866 [250, [revert_cs_label]],
868 [248, [revert_utf8]],
869 [247, [revert_booktabs]],
870 [246, [revert_font_settings]],
871 [245, [revert_framed]]]
874 if __name__ == "__main__":