1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2008 The LyX Team <lyx-devel@lists.lyx.org>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 """ Convert files to the file format generated by lyx 1.6"""
25 from parser_tools import find_token, find_end_of, find_tokens, get_value
27 # Provide support for both python 2 and 3
28 PY2 = sys.version_info[0] == 2
31 # End of code to support for both python 2 and 3
33 ####################################################################
34 # Private helper functions
37 def get_value_string(lines, token, start, end = 0, trim = False, default = ""):
38 """ get_value_string(lines, token, start[[, end], trim, default]) -> string
40 Return tokens after token as string, in lines, where
41 token is the first element. When trim is used, the first and last character
42 of the string is trimmed."""
44 val = get_value(lines, token, start, end, "")
52 def find_end_of_inset(lines, i):
53 " Find end of inset, where lines[i] is included."
54 return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
58 # document.body[i] = wrap_insert_ert(...)
59 # wrap_into_ert may returns a multiline string, which should NOT appear
60 # in document.body. Instead, do something like this:
61 # subst = wrap_inset_ert(...)
62 # subst = subst.split('\n')
63 # document.body[i:i+1] = subst
65 # where the last statement resets the counter to accord with the added
67 def wrap_into_ert(string, src, dst):
68 '''Within string, replace occurrences of src with dst, wrapped into ERT
69 E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is:
70 sch<ERT>\\backslash</ERT>"on'''
71 return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
72 + dst + '\n\\end_layout\n\\end_inset\n')
74 def put_cmd_in_ert(string):
75 for rep in unicode_reps:
76 string = string.replace(rep[1], rep[0].replace('\\\\', '\\'))
77 string = string.replace('\\', "\\backslash\n")
78 string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n" \
79 + string + "\n\\end_layout\n\\end_inset"
82 def add_to_preamble(document, text):
83 """ Add text to the preamble if it is not already there.
84 Only the first line is checked!"""
86 if find_token(document.preamble, text[0], 0) != -1:
89 document.preamble.extend(text)
91 def insert_to_preamble(index, document, text):
92 """ Insert text to the preamble at a given line"""
94 document.preamble.insert(index, text)
96 # Convert a LyX length into a LaTeX length
98 units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
99 "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
100 "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
102 # Convert LyX units to LaTeX units
103 for unit in list(units.keys()):
104 if len.find(unit) != -1:
105 len = '%f' % (len2value(len) / 100)
106 len = len.strip('0') + units[unit]
111 # Return the value of len without the unit in numerical form.
113 result = re.search('([+-]?[0-9.]+)', len)
115 return float(result.group(1))
116 # No number means 1.0
119 # Unfortunately, this doesn't really work, since Standard isn't always default.
120 # But it's as good as we can do right now.
121 def find_default_layout(document, start, end):
122 l = find_token(document.body, "\\begin_layout Standard", start, end)
124 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
126 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
129 def get_option(document, m, option, default):
130 l = document.body[m].find(option)
133 val = document.body[m][l:].split('"')[1]
136 def remove_option(document, m, option):
137 l = document.body[m].find(option)
139 val = document.body[m][l:].split('"')[1]
140 document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
143 def set_option(document, m, option, value):
144 l = document.body[m].find(option)
146 oldval = document.body[m][l:].split('"')[1]
147 l = l + len(option + '="')
148 document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
150 document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
154 # FIXME: Use the version in unicode_symbols.py which has some bug fixes
155 def read_unicodesymbols():
156 " Read the unicodesymbols list of unicode characters and corresponding commands."
157 pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
158 fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
160 # Two backslashes, followed by some non-word character, and then a character
161 # in brackets. The idea is to check for constructs like: \"{u}, which is how
162 # they are written in the unicodesymbols file; but they can also be written
163 # as: \"u or even \" u.
164 r = re.compile(r'\\\\(\W)\{(\w)\}')
165 for line in fp.readlines():
166 if line[0] != '#' and line.strip() != "":
167 line=line.replace(' "',' ') # remove all quotation marks with spaces before
168 line=line.replace('" ',' ') # remove all quotation marks with spaces after
169 line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
171 [ucs4,command,dead] = line.split(None,2)
172 if command[0:1] != "\\":
174 spec_chars.append([command, unichr(eval(ucs4))])
180 # If the character is a double-quote, then we need to escape it, too,
181 # since it is done that way in the LyX file.
182 if m.group(1) == "\"":
185 command += m.group(1) + m.group(2)
186 commandbl += m.group(1) + ' ' + m.group(2)
187 spec_chars.append([command, unichr(eval(ucs4))])
188 spec_chars.append([commandbl, unichr(eval(ucs4))])
193 def extract_argument(line):
194 'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
199 bracere = re.compile("(\s*)(.*)")
200 n = bracere.match(line)
201 whitespace = n.group(1)
204 if brace != "[" and brace != "{":
228 # We never found the matching brace
229 # So, to be on the safe side, let's just return everything
230 # which will then get wrapped as ERT
232 return (line[:pos + 1], line[pos + 1:])
235 def latex2ert(line, isindex):
236 '''Converts LaTeX commands into ERT. line may well be a multi-line
237 string when it is returned.'''
242 ## FIXME Escaped \ ??
243 # This regex looks for a LaTeX command---i.e., something of the form
244 # "\alPhaStuFF", or "\X", where X is any character---where the command
245 # may also be preceded by an additional backslash, which is how it would
246 # appear (e.g.) in an InsetIndex.
247 labelre = re.compile(r'(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)')
249 m = labelre.match(line)
256 (arg, rest) = extract_argument(end)
261 # If we wanted to put labels into an InsetLabel, for example, then we
262 # would just need to test here for cmd == "label" and then take some
263 # appropriate action, i.e., to use arg to get the content and then
264 # wrap it appropriately.
265 cmd = put_cmd_in_ert(cmd)
266 retval += "\n" + cmd + "\n"
268 m = labelre.match(line)
269 # put all remaining braces in ERT
270 line = wrap_into_ert(line, '}', '}')
271 line = wrap_into_ert(line, '{', '{')
273 # active character that is not available in all font encodings
274 line = wrap_into_ert(line, '|', '|')
279 unicode_reps = read_unicodesymbols()
282 #Might should do latex2ert first, then deal with stuff that DOESN'T
283 #end up inside ERT. That routine could be modified so that it returned
284 #a list of lines, and we could then skip ERT bits and only deal with
286 def latex2lyx(data, isindex):
287 '''Takes a string, possibly multi-line, and returns the result of
288 converting LaTeX constructs into LyX constructs. Returns a list of
289 lines, suitable for insertion into document.body.
290 The bool isindex specifies whether we are in an index macro (which
291 has some specific active characters that need to be ERTed).'''
297 # Convert LaTeX to Unicode
298 # Commands of this sort need to be checked to make sure they are
299 # followed by a non-alpha character, lest we replace too much.
300 hardone = re.compile(r'^\\\\[a-zA-Z]+$')
302 for rep in unicode_reps:
303 if hardone.match(rep[0]):
306 pos = data.find(rep[0], pos)
309 nextpos = pos + len(rep[0])
310 if nextpos < len(data) and data[nextpos].isalpha():
311 # not the end of that command
314 data = data[:pos] + rep[1] + data[nextpos:]
317 data = data.replace(rep[0], rep[1])
321 data = wrap_into_ert(data, r'\"', '"')
323 data = data.replace('\\\\', '\\')
326 mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
327 lines = data.split('\n')
329 #document.warning("LINE: " + line)
330 #document.warning(str(i) + ":" + document.body[i])
331 #document.warning("LAST: " + document.body[-1])
336 f = m.group(2).replace('\\\\', '\\')
340 s = latex2ert(s, isindex)
341 subst = s.split('\n')
343 retval.append("\\begin_inset Formula " + f)
344 retval.append("\\end_inset")
346 # Handle whatever is left, which is just text
347 g = latex2ert(g, isindex)
348 subst = g.split('\n')
353 def lyxline2latex(document, line, inert):
354 'Convert some LyX stuff into corresponding LaTeX stuff line-wise, as best we can.'
355 if line.startswith("\\begin_inset Formula"):
357 elif line.startswith("\\begin_inset Quotes"):
358 # For now, we do a very basic reversion. Someone who understands
359 # quotes is welcome to fix it up.
360 qtype = line[20:].strip()
374 elif line.isspace() or \
375 line.startswith("\\begin_layout") or \
376 line.startswith("\\end_layout") or \
377 line.startswith("\\begin_inset") or \
378 line.startswith("\\end_inset") or \
379 line.startswith("\\lang") or \
380 line.strip() == "status collapsed" or \
381 line.strip() == "status open":
385 # this needs to be added to the preamble because of cases like
386 # \textmu, \textbackslash, etc.
387 add_to_preamble(document, ['% added by lyx2lyx for converted entries',
388 '\\@ifundefined{textmu}',
389 ' {\\usepackage{textcomp}}{}'])
390 # a lossless reversion is not possible
391 # try at least to handle some common insets and settings
393 line = line.replace(r'\backslash', '\\')
395 line = line.replace('&', '\\&{}')
396 line = line.replace('#', '\\#{}')
397 line = line.replace('^', '\\^{}')
398 line = line.replace('%', '\\%{}')
399 line = line.replace('_', '\\_{}')
400 line = line.replace('$', '\\${}')
402 # Do the LyX text --> LaTeX conversion
403 for rep in unicode_reps:
404 line = line.replace(rep[1], rep[0].replace('\\\\', '\\') + "{}")
405 line = line.replace(r'\backslash', r'\textbackslash{}')
406 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
407 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
408 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
409 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
410 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
411 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
412 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
413 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
414 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
418 def lyx2latex(document, lines):
419 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
420 # clean up multiline stuff
424 for curline in range(len(lines)):
425 line = lines[curline]
426 if line.startswith("\\begin_inset ERT"):
427 # We don't want to replace things inside ERT, so figure out
428 # where the end of the inset is.
429 ert_end = find_end_of_inset(lines, curline + 1)
431 inert = ert_end >= curline
432 content += lyxline2latex(document, lines[curline], inert)
437 ####################################################################
439 def convert_ltcaption(document):
442 i = find_token(document.body, "\\begin_inset Tabular", i)
445 j = find_end_of_inset(document.body, i + 1)
447 document.warning("Malformed LyX document: Could not find end of tabular.")
451 nrows = int(document.body[i+1].split('"')[3])
452 ncols = int(document.body[i+1].split('"')[5])
455 for k in range(nrows):
456 m = find_token(document.body, "<row", m)
459 for k in range(ncols):
460 m = find_token(document.body, "<cell", m)
462 mend = find_token(document.body, "</cell>", m + 1)
463 # first look for caption insets
464 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
465 # then look for ERT captions
467 mcap = find_token(document.body, "caption", m + 1, mend)
469 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
472 if caption == 'true':
474 set_option(document, r, 'caption', 'true')
475 set_option(document, m, 'multicolumn', '1')
476 set_option(document, m, 'bottomline', 'false')
477 set_option(document, m, 'topline', 'false')
478 set_option(document, m, 'rightline', 'false')
479 set_option(document, m, 'leftline', 'false')
480 #j = find_end_of_inset(document.body, j + 1)
482 set_option(document, m, 'multicolumn', '2')
489 #FIXME Use of wrap_into_ert can confuse lyx2lyx
490 def revert_ltcaption(document):
493 i = find_token(document.body, "\\begin_inset Tabular", i)
496 j = find_end_of_inset(document.body, i + 1)
498 document.warning("Malformed LyX document: Could not find end of tabular.")
503 nrows = int(document.body[i+1].split('"')[3])
504 ncols = int(document.body[i+1].split('"')[5])
506 for k in range(nrows):
507 m = find_token(document.body, "<row", m)
508 caption = get_option(document, m, 'caption', 'false')
509 if caption == 'true':
510 remove_option(document, m, 'caption')
511 for k in range(ncols):
512 m = find_token(document.body, "<cell", m)
513 remove_option(document, m, 'multicolumn')
515 m = find_token(document.body, "\\begin_inset Caption", m)
518 m = find_end_of_inset(document.body, m + 1)
519 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
525 def convert_tablines(document):
528 i = find_token(document.body, "\\begin_inset Tabular", i)
530 # LyX 1.3 inserted an extra space between \begin_inset
531 # and Tabular so let us try if this is the case and fix it.
532 i = find_token(document.body, "\\begin_inset Tabular", i)
536 document.body[i] = "\\begin_inset Tabular"
537 j = find_end_of_inset(document.body, i + 1)
539 document.warning("Malformed LyX document: Could not find end of tabular.")
544 nrows = int(document.body[i+1].split('"')[3])
545 ncols = int(document.body[i+1].split('"')[5])
548 for k in range(ncols):
549 m = find_token(document.body, "<column", m)
550 left = get_option(document, m, 'leftline', 'false')
551 right = get_option(document, m, 'rightline', 'false')
552 col_info.append([left, right])
553 remove_option(document, m, 'leftline')
554 remove_option(document, m, 'rightline')
558 for k in range(nrows):
559 m = find_token(document.body, "<row", m)
560 top = get_option(document, m, 'topline', 'false')
561 bottom = get_option(document, m, 'bottomline', 'false')
562 row_info.append([top, bottom])
563 remove_option(document, m, 'topline')
564 remove_option(document, m, 'bottomline')
569 for k in range(nrows*ncols):
570 m = find_token(document.body, "<cell", m)
571 mc_info.append(get_option(document, m, 'multicolumn', '0'))
574 for l in range(nrows):
575 for k in range(ncols):
576 m = find_token(document.body, '<cell', m)
577 if mc_info[l*ncols + k] == '0':
578 r = set_option(document, m, 'topline', row_info[l][0])
579 r = set_option(document, m, 'bottomline', row_info[l][1])
580 r = set_option(document, m, 'leftline', col_info[k][0])
581 r = set_option(document, m, 'rightline', col_info[k][1])
582 elif mc_info[l*ncols + k] == '1':
584 while s < ncols and mc_info[l*ncols + s] == '2':
586 if s < ncols and mc_info[l*ncols + s] != '1':
587 r = set_option(document, m, 'rightline', col_info[k][1])
588 if k > 0 and mc_info[l*ncols + k - 1] == '0':
589 r = set_option(document, m, 'leftline', col_info[k][0])
594 def revert_tablines(document):
597 i = find_token(document.body, "\\begin_inset Tabular", i)
600 j = find_end_of_inset(document.body, i)
602 document.warning("Malformed LyX document: Could not find end of tabular.")
607 nrows = int(document.body[i+1].split('"')[3])
608 ncols = int(document.body[i+1].split('"')[5])
611 for k in range(nrows*ncols):
612 m = find_token(document.body, "<cell", m)
613 top = get_option(document, m, 'topline', 'false')
614 bottom = get_option(document, m, 'bottomline', 'false')
615 left = get_option(document, m, 'leftline', 'false')
616 right = get_option(document, m, 'rightline', 'false')
617 lines.append([top, bottom, left, right])
620 # we will want to ignore longtable captions
623 for k in range(nrows):
624 m = find_token(document.body, "<row", m)
625 caption = get_option(document, m, 'caption', 'false')
626 caption_info.append([caption])
631 for k in range(ncols):
632 m = find_token(document.body, "<column", m)
634 for l in range(nrows):
635 left = lines[l*ncols + k][2]
636 if left == 'false' and caption_info[l] == 'false':
638 set_option(document, m, 'leftline', left)
640 for l in range(nrows):
641 right = lines[l*ncols + k][3]
642 if right == 'false' and caption_info[l] == 'false':
644 set_option(document, m, 'rightline', right)
648 for k in range(nrows):
649 m = find_token(document.body, "<row", m)
651 for l in range(ncols):
652 top = lines[k*ncols + l][0]
655 if caption_info[k] == 'false':
657 set_option(document, m, 'topline', top)
659 for l in range(ncols):
660 bottom = lines[k*ncols + l][1]
661 if bottom == 'false':
663 if caption_info[k] == 'false':
665 set_option(document, m, 'bottomline', bottom)
671 def fix_wrong_tables(document):
674 i = find_token(document.body, "\\begin_inset Tabular", i)
677 j = find_end_of_inset(document.body, i + 1)
679 document.warning("Malformed LyX document: Could not find end of tabular.")
684 nrows = int(document.body[i+1].split('"')[3])
685 ncols = int(document.body[i+1].split('"')[5])
687 for l in range(nrows):
689 for k in range(ncols):
690 m = find_token(document.body, '<cell', m)
692 if document.body[m].find('multicolumn') != -1:
693 multicol_cont = int(document.body[m].split('"')[1])
695 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
696 document.body[m] = document.body[m][:5] + document.body[m][21:]
699 prev_multicolumn = multicol_cont
706 def close_begin_deeper(document):
710 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
715 if document.body[i][:13] == "\\begin_deeper":
722 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
725 def long_charstyle_names(document):
728 i = find_token(document.body, "\\begin_inset CharStyle", i)
731 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
734 def revert_long_charstyle_names(document):
737 i = find_token(document.body, "\\begin_inset CharStyle", i)
740 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
744 def axe_show_label(document):
747 i = find_token(document.body, "\\begin_inset CharStyle", i)
750 if document.body[i + 1].find("show_label") != -1:
751 if document.body[i + 1].find("true") != -1:
752 document.body[i + 1] = "status open"
753 del document.body[ i + 2]
755 if document.body[i + 1].find("false") != -1:
756 document.body[i + 1] = "status collapsed"
757 del document.body[ i + 2]
759 document.warning("Malformed LyX document: show_label neither false nor true.")
761 document.warning("Malformed LyX document: show_label missing in CharStyle.")
766 def revert_show_label(document):
769 i = find_token(document.body, "\\begin_inset CharStyle", i)
772 if document.body[i + 1].find("status open") != -1:
773 document.body.insert(i + 1, "show_label true")
775 if document.body[i + 1].find("status collapsed") != -1:
776 document.body.insert(i + 1, "show_label false")
778 document.warning("Malformed LyX document: no legal status line in CharStyle.")
781 def revert_begin_modules(document):
784 i = find_token(document.header, "\\begin_modules", i)
787 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
789 # this should not happen
791 document.header[i : j + 1] = []
793 def convert_flex(document):
794 "Convert CharStyle to Flex"
797 i = find_token(document.body, "\\begin_inset CharStyle", i)
800 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
802 def revert_flex(document):
803 "Revert Flex to CharStyle"
806 i = find_token(document.body, "\\begin_inset Flex", i)
809 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
812 def revert_pdf_options(document):
813 "Revert PDF options for hyperref."
814 # store the PDF options and delete the entries from the Lyx file
822 bookmarksnumbered = ""
824 bookmarksopenlevel = ""
832 i = find_token(document.header, "\\use_hyperref", i)
834 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
835 del document.header[i]
836 i = find_token(document.header, "\\pdf_store_options", i)
838 del document.header[i]
839 i = find_token(document.header, "\\pdf_title", 0)
841 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
842 title = ' pdftitle={' + title + '}'
843 del document.header[i]
844 i = find_token(document.header, "\\pdf_author", 0)
846 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
848 author = ' pdfauthor={' + author + '}'
850 author = ',\n pdfauthor={' + author + '}'
851 del document.header[i]
852 i = find_token(document.header, "\\pdf_subject", 0)
854 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
855 if title == "" and author == "":
856 subject = ' pdfsubject={' + subject + '}'
858 subject = ',\n pdfsubject={' + subject + '}'
859 del document.header[i]
860 i = find_token(document.header, "\\pdf_keywords", 0)
862 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
863 if title == "" and author == "" and subject == "":
864 keywords = ' pdfkeywords={' + keywords + '}'
866 keywords = ',\n pdfkeywords={' + keywords + '}'
867 del document.header[i]
868 i = find_token(document.header, "\\pdf_bookmarks", 0)
870 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
871 bookmarks = ',\n bookmarks=' + bookmarks
872 del document.header[i]
873 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
875 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
876 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
877 del document.header[i]
878 i = find_token(document.header, "\\pdf_bookmarksopen", i)
880 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
881 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
882 del document.header[i]
883 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
885 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
886 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
887 del document.header[i]
888 i = find_token(document.header, "\\pdf_breaklinks", i)
890 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
891 breaklinks = ',\n breaklinks=' + breaklinks
892 del document.header[i]
893 i = find_token(document.header, "\\pdf_pdfborder", i)
895 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
896 if pdfborder == 'true':
897 pdfborder = ',\n pdfborder={0 0 0}'
899 pdfborder = ',\n pdfborder={0 0 1}'
900 del document.header[i]
901 i = find_token(document.header, "\\pdf_colorlinks", i)
903 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
904 colorlinks = ',\n colorlinks=' + colorlinks
905 del document.header[i]
906 i = find_token(document.header, "\\pdf_backref", i)
908 backref = get_value_string(document.header, '\\pdf_backref', 0)
909 backref = ',\n backref=' + backref
910 del document.header[i]
911 i = find_token(document.header, "\\pdf_pagebackref", i)
913 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
914 pagebackref = ',\n pagebackref=' + pagebackref
915 del document.header[i]
916 i = find_token(document.header, "\\pdf_pagemode", 0)
918 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
919 pagemode = ',\n pdfpagemode=' + pagemode
920 del document.header[i]
921 i = find_token(document.header, "\\pdf_quoted_options", 0)
923 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
924 if title == "" and author == "" and subject == "" and keywords == "":
925 otheroptions = ' ' + otheroptions
927 otheroptions = ',\n ' + otheroptions
928 del document.header[i]
930 # write to the preamble when hyperref was used
932 # preamble write preparations
933 # bookmark numbers are only output when they are turned on
934 if bookmarksopen == ',\n bookmarksopen=true':
935 bookmarksopen = bookmarksopen + bookmarksopenlevel
936 if bookmarks == ',\n bookmarks=true':
937 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
939 bookmarks = bookmarks
940 # hypersetup is only output when there are things to be set up
941 setupstart = '\\hypersetup{%\n'
943 if otheroptions == "" and title == "" and author == ""\
944 and subject == "" and keywords == "":
948 # babel must be loaded before hyperref and hyperref the first part
949 # of the preamble, like in LyX 1.6
950 insert_to_preamble(0, document,
951 '% Commands inserted by lyx2lyx for PDF properties\n'
952 + '\\usepackage{babel}\n'
953 + '\\usepackage[unicode=true'
972 def remove_inzip_options(document):
973 "Remove inzipName and embed options from the Graphics inset"
976 i = find_token(document.body, "\\begin_inset Graphics", i)
979 j = find_end_of_inset(document.body, i + 1)
982 document.warning("Malformed LyX document: Could not find end of graphics inset.")
985 # If there's a inzip param, just remove that
986 k = find_token(document.body, "\tinzipName", i + 1, j)
989 # embed option must follow the inzipName option
990 del document.body[k+1]
994 def convert_inset_command(document):
997 \begin_inset LatexCommand cmd
999 \begin_inset CommandInset InsetType
1004 i = find_token(document.body, "\\begin_inset LatexCommand", i)
1007 line = document.body[i]
1008 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
1010 cmdName = m.group(1)
1012 #this is adapted from factory.cpp
1013 if cmdName[0:4].lower() == "cite":
1014 insetName = "citation"
1015 elif cmdName == "url" or cmdName == "htmlurl":
1017 elif cmdName[-3:] == "ref":
1019 elif cmdName == "tableofcontents":
1021 elif cmdName == "printnomenclature":
1022 insetName = "nomencl_print"
1023 elif cmdName == "printindex":
1024 insetName = "index_print"
1027 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
1028 document.body[i : i+1] = insertion
1031 def revert_inset_command(document):
1034 \begin_inset CommandInset InsetType
1037 \begin_inset LatexCommand cmd
1038 Some insets may end up being converted to insets earlier versions of LyX
1039 will not be able to recognize. Not sure what to do about that.
1043 i = find_token(document.body, "\\begin_inset CommandInset", i)
1046 nextline = document.body[i+1]
1047 r = re.compile(r'LatexCommand\s+(.*)$')
1048 m = r.match(nextline)
1050 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
1053 cmdName = m.group(1)
1054 insertion = ["\\begin_inset LatexCommand " + cmdName]
1055 document.body[i : i+2] = insertion
1058 def convert_wrapfig_options(document):
1059 "Convert optional options for wrap floats (wrapfig)."
1060 # adds the tokens "lines", "placement", and "overhang"
1063 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1066 document.body.insert(i + 1, "lines 0")
1067 j = find_token(document.body, "placement", i)
1068 # placement can be already set or not; if not, set it
1070 document.body.insert(i + 3, "overhang 0col%")
1072 document.body.insert(i + 2, "placement o")
1073 document.body.insert(i + 3, "overhang 0col%")
1077 def revert_wrapfig_options(document):
1078 "Revert optional options for wrap floats (wrapfig)."
1081 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1084 j = find_end_of_inset(document.body, i)
1086 document.warning("Can't find end of Wrap inset at line " + str(i))
1089 k = find_default_layout(document, i, j)
1091 document.warning("Can't find default layout for Wrap figure!")
1094 # Options should be between i and k now
1095 l = find_token(document.body, "lines", i, k)
1097 document.warning("Can't find lines option for Wrap figure!")
1100 m = find_token(document.body, "overhang", i + 1, k)
1102 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1105 # Do these in reverse order
1106 del document.body[m]
1107 del document.body[l]
1111 def convert_latexcommand_index(document):
1112 "Convert from LatexCommand form to collapsable form."
1114 r1 = re.compile('name "(.*)"')
1116 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1119 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1122 j = find_end_of_inset(document.body, i + 1)
1124 document.warning("Unable to find end of index inset at line " + str(i) + "!")
1127 m = r1.match(document.body[i + 2])
1129 document.warning("Unable to match: " + document.body[i+2])
1130 # this can happen with empty index insets!
1133 fullcontent = m.group(1)
1134 linelist = latex2lyx(fullcontent, True)
1135 #document.warning(fullcontent)
1137 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1138 linelist + ["\\end_layout"]
1139 document.body[i : j] = linelist
1140 i += len(linelist) - (j - i)
1143 def revert_latexcommand_index(document):
1144 "Revert from collapsable form to LatexCommand form."
1147 i = find_token(document.body, "\\begin_inset Index", i)
1150 j = find_end_of_inset(document.body, i + 1)
1154 content = lyx2latex(document, document.body[i:j])
1156 content = content.replace('"', r'\"')
1157 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1158 "name " + '"' + content + '"', ""]
1162 def revert_wraptable(document):
1163 "Revert wrap table to wrap figure."
1166 i = find_token(document.body, "\\begin_inset Wrap table", i)
1169 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1173 def revert_vietnamese(document):
1174 "Set language Vietnamese to English"
1175 # Set document language from Vietnamese to English
1177 if document.language == "vietnamese":
1178 document.language = "english"
1179 i = find_token(document.header, "\\language", 0)
1181 document.header[i] = "\\language english"
1184 j = find_token(document.body, "\\lang vietnamese", j)
1187 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1191 def convert_japanese_cjk(document):
1192 "Set language japanese to japanese-cjk"
1193 # Set document language from japanese-plain to japanese
1195 if document.language == "japanese":
1196 document.language = "japanese-cjk"
1197 i = find_token(document.header, "\\language", 0)
1199 document.header[i] = "\\language japanese-cjk"
1202 j = find_token(document.body, "\\lang japanese", j)
1205 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1209 def revert_japanese(document):
1210 "Set language japanese-plain to japanese"
1211 # Set document language from japanese-plain to japanese
1213 if document.language == "japanese-plain":
1214 document.language = "japanese"
1215 i = find_token(document.header, "\\language", 0)
1217 document.header[i] = "\\language japanese"
1220 j = find_token(document.body, "\\lang japanese-plain", j)
1223 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1227 def revert_japanese_cjk(document):
1228 "Set language japanese-cjk to japanese"
1229 # Set document language from japanese-plain to japanese
1231 if document.language == "japanese-cjk":
1232 document.language = "japanese"
1233 i = find_token(document.header, "\\language", 0)
1235 document.header[i] = "\\language japanese"
1238 j = find_token(document.body, "\\lang japanese-cjk", j)
1241 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1245 def revert_japanese_encoding(document):
1246 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1247 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1249 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1251 document.header[i] = "\\inputencoding EUC-JP"
1253 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1255 document.header[j] = "\\inputencoding JIS"
1257 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1258 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1259 document.header[k] = "\\inputencoding UTF8"
1262 def revert_inset_info(document):
1263 'Replace info inset with its content'
1266 i = find_token(document.body, '\\begin_inset Info', i)
1269 j = find_end_of_inset(document.body, i + 1)
1272 document.warning("Malformed LyX document: Could not find end of Info inset.")
1277 for k in range(i, j+1):
1278 if document.body[k].startswith("arg"):
1279 arg = document.body[k][3:].strip()
1280 # remove embracing quotation marks
1283 if arg[len(arg) - 1] == '"':
1284 arg = arg[:len(arg) - 1]
1285 # \" to straight quote
1286 arg = arg.replace(r'\"', '"')
1288 arg = arg.replace(r'\\', "\\backslash\n")
1289 if document.body[k].startswith("type"):
1290 type = document.body[k][4:].strip().strip('"')
1291 # I think there is a newline after \\end_inset, which should be removed.
1292 if document.body[j + 1].strip() == "":
1293 document.body[i : (j + 2)] = [type + ':' + arg]
1295 document.body[i : (j + 1)] = [type + ':' + arg]
1298 def convert_pdf_options(document):
1299 # Set the pdfusetitle tag, delete the pdf_store_options,
1300 # set quotes for bookmarksopenlevel"
1301 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1303 k = find_token(document.header, "\\use_hyperref", 0)
1304 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1305 k = find_token(document.header, "\\pdf_store_options", 0)
1307 del document.header[k]
1308 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1310 document.header[i] = document.header[i].replace('"', '')
1313 def revert_pdf_options_2(document):
1314 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1315 k = find_token(document.header, "\\use_hyperref", 0)
1316 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1318 del document.header[i]
1319 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1321 values = document.header[i].split()
1322 values[1] = ' "' + values[1] + '"'
1323 document.header[i] = ''.join(values)
1326 def convert_htmlurl(document):
1327 'Convert "htmlurl" to "href" insets for docbook'
1328 if document.backend != "docbook":
1332 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1335 document.body[i] = "\\begin_inset CommandInset href"
1336 document.body[i + 1] = "LatexCommand href"
1340 def convert_url(document):
1341 'Convert url insets to url charstyles'
1342 if document.backend == "docbook":
1346 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1349 n = find_token(document.body, "name", i)
1351 # place the URL name in typewriter before the new URL insert
1352 # grab the name 'bla' from the e.g. the line 'name "bla"',
1353 # therefore start with the 6th character
1354 name = document.body[n][6:-1]
1355 newname = [name + " "]
1356 document.body[i:i] = newname
1358 j = find_token(document.body, "target", i)
1360 document.warning("Malformed LyX document: Can't find target for url inset")
1363 target = document.body[j][8:-1]
1364 k = find_token(document.body, "\\end_inset", j)
1366 document.warning("Malformed LyX document: Can't find end of url inset")
1369 newstuff = ["\\begin_inset Flex URL",
1370 "status collapsed", "",
1371 "\\begin_layout Standard",
1376 document.body[i:k] = newstuff
1377 i = i + len(newstuff)
1379 def convert_ams_classes(document):
1380 tc = document.textclass
1381 if (tc != "amsart" and tc != "amsart-plain" and
1382 tc != "amsart-seq" and tc != "amsbook"):
1384 if tc == "amsart-plain":
1385 document.textclass = "amsart"
1386 document.set_textclass()
1387 document.add_module("Theorems (Starred)")
1389 if tc == "amsart-seq":
1390 document.textclass = "amsart"
1391 document.set_textclass()
1392 document.add_module("Theorems (AMS)")
1394 #Now we want to see if any of the environments in the extended theorems
1395 #module were used in this document. If so, we'll add that module, too.
1396 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1397 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1400 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1403 i = find_token(document.body, "\\begin_layout", i)
1406 m = r.match(document.body[i])
1408 # This is an empty layout
1409 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1413 if layouts.count(m) != 0:
1414 document.add_module("Theorems (AMS-Extended)")
1418 def revert_href(document):
1419 'Reverts hyperlink insets (href) to url insets (url)'
1422 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1425 document.body[i : i + 2] = \
1426 ["\\begin_inset CommandInset url", "LatexCommand url"]
1429 def revert_url(document):
1430 'Reverts Flex URL insets to old-style URL insets'
1433 i = find_token(document.body, "\\begin_inset Flex URL", i)
1436 j = find_end_of_inset(document.body, i)
1438 document.warning("Can't find end of inset in revert_url!")
1440 k = find_default_layout(document, i, j)
1442 document.warning("Can't find default layout in revert_url!")
1445 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1446 if l == -1 or l >= j:
1447 document.warning("Can't find end of default layout in revert_url!")
1450 # OK, so the inset's data is between lines k and l.
1451 data = " ".join(document.body[k+1:l])
1453 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1455 document.body[i:j+1] = newinset
1456 i = i + len(newinset)
1459 def convert_include(document):
1460 'Converts include insets to new format.'
1462 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1464 i = find_token(document.body, "\\begin_inset Include", i)
1467 line = document.body[i]
1468 previewline = document.body[i + 1]
1471 document.warning("Unable to match line " + str(i) + " of body!")
1477 insertion = ["\\begin_inset CommandInset include",
1478 "LatexCommand " + cmd, previewline,
1479 "filename \"" + fn + "\""]
1482 insertion.append("lstparams " + '"' + opt + '"')
1484 document.body[i : i + 2] = insertion
1488 def revert_include(document):
1489 'Reverts include insets to old format.'
1491 r0 = re.compile('preview.*')
1492 r1 = re.compile('LatexCommand (.+)')
1493 r2 = re.compile('filename "(.+)"')
1494 r3 = re.compile('lstparams "(.*)"')
1496 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1500 m = r1.match(document.body[nextline])
1502 document.warning("Malformed LyX document: No LatexCommand line for `" +
1503 document.body[i] + "' on line " + str(i) + ".")
1508 if r0.match(document.body[nextline]):
1509 previewline = document.body[nextline]
1513 m = r2.match(document.body[nextline])
1515 document.warning("Malformed LyX document: No filename line for `" + \
1516 document.body[i] + "' on line " + str(i) + ".")
1522 if (cmd == "lstinputlisting"):
1523 m = r3.match(document.body[nextline])
1525 options = m.group(1)
1528 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1530 newline += ("[" + options + "]")
1531 insertion = [newline]
1532 if previewline != "":
1533 insertion.append(previewline)
1534 document.body[i : nextline] = insertion
1538 def revert_albanian(document):
1539 "Set language Albanian to English"
1541 if document.language == "albanian":
1542 document.language = "english"
1543 i = find_token(document.header, "\\language", 0)
1545 document.header[i] = "\\language english"
1548 j = find_token(document.body, "\\lang albanian", j)
1551 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1555 def revert_lowersorbian(document):
1556 "Set language lower Sorbian to English"
1558 if document.language == "lowersorbian":
1559 document.language = "english"
1560 i = find_token(document.header, "\\language", 0)
1562 document.header[i] = "\\language english"
1565 j = find_token(document.body, "\\lang lowersorbian", j)
1568 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1572 def revert_uppersorbian(document):
1573 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1575 if document.language == "uppersorbian":
1576 document.language = "usorbian"
1577 i = find_token(document.header, "\\language", 0)
1579 document.header[i] = "\\language usorbian"
1582 j = find_token(document.body, "\\lang uppersorbian", j)
1585 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1589 def convert_usorbian(document):
1590 "Set language usorbian to uppersorbian"
1592 if document.language == "usorbian":
1593 document.language = "uppersorbian"
1594 i = find_token(document.header, "\\language", 0)
1596 document.header[i] = "\\language uppersorbian"
1599 j = find_token(document.body, "\\lang usorbian", j)
1602 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1606 def convert_macro_global(document):
1607 "Remove TeX code command \global when it is in front of a macro"
1608 # math macros are nowadays already defined \global, so that an additional
1609 # \global would make the document uncompilable, see
1610 # http://www.lyx.org/trac/ticket/5371
1611 # We're looking for something like this:
1615 # \begin_layout Plain Layout
1625 # \begin_inset FormulaMacro
1626 # \renewcommand{\foo}{123}
1630 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1633 # if i <= 13, then there isn't enough room for the ERT
1637 if document.body[i-6] == "global":
1638 del document.body[i-13 : i]
1644 def revert_macro_optional_params(document):
1645 "Convert macro definitions with optional parameters into ERTs"
1646 # Stub to convert macro definitions with one or more optional parameters
1647 # into uninterpreted ERT insets
1650 def revert_hyperlinktype(document):
1651 'Reverts hyperlink type'
1655 i = find_token(document.body, "target", i)
1658 j = find_token(document.body, "type", i)
1662 del document.body[j]
1666 def revert_pagebreak(document):
1667 'Reverts pagebreak to ERT'
1670 i = find_token(document.body, "\\pagebreak", i)
1673 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1674 '\\begin_layout Standard\n\n\n\\backslash\n' \
1675 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1679 def revert_linebreak(document):
1680 'Reverts linebreak to ERT'
1683 i = find_token(document.body, "\\linebreak", i)
1686 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1687 '\\begin_layout Standard\n\n\n\\backslash\n' \
1688 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1692 def revert_latin(document):
1693 "Set language Latin to English"
1695 if document.language == "latin":
1696 document.language = "english"
1697 i = find_token(document.header, "\\language", 0)
1699 document.header[i] = "\\language english"
1702 j = find_token(document.body, "\\lang latin", j)
1705 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1709 def revert_samin(document):
1710 "Set language North Sami to English"
1712 if document.language == "samin":
1713 document.language = "english"
1714 i = find_token(document.header, "\\language", 0)
1716 document.header[i] = "\\language english"
1719 j = find_token(document.body, "\\lang samin", j)
1722 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1726 def convert_serbocroatian(document):
1727 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1729 if document.language == "serbocroatian":
1730 document.language = "croatian"
1731 i = find_token(document.header, "\\language", 0)
1733 document.header[i] = "\\language croatian"
1736 j = find_token(document.body, "\\lang serbocroatian", j)
1739 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1743 def convert_framed_notes(document):
1744 "Convert framed notes to boxes. "
1747 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1750 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1759 'height_special "totalheight"']
1760 document.body[i:i+1] = subst
1764 def convert_module_names(document):
1765 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1766 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1767 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1768 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1769 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1770 modlist = document.get_module_list()
1771 if len(modlist) == 0:
1775 if mod in modulemap:
1776 newmodlist.append(modulemap[mod])
1778 document.warning("Can't find module %s in the module map!" % mod)
1779 newmodlist.append(mod)
1780 document.set_module_list(newmodlist)
1783 def revert_module_names(document):
1784 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1785 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1786 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1787 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1788 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1789 modlist = document.get_module_list()
1790 if len(modlist) == 0:
1794 if mod in modulemap:
1795 newmodlist.append(modulemap[mod])
1797 document.warning("Can't find module %s in the module map!" % mod)
1798 newmodlist.append(mod)
1799 document.set_module_list(newmodlist)
1802 def revert_colsep(document):
1803 i = find_token(document.header, "\\columnsep", 0)
1806 colsepline = document.header[i]
1807 r = re.compile(r'\\columnsep (.*)')
1808 m = r.match(colsepline)
1810 document.warning("Malformed column separation line!")
1813 del document.header[i]
1814 #it seems to be safe to add the package even if it is already used
1815 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1817 add_to_preamble(document, pretext)
1820 def revert_framed_notes(document):
1821 "Revert framed boxes to notes. "
1824 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1828 j = find_end_of_inset(document.body, i + 1)
1831 document.warning("Malformed LyX document: Could not find end of Box inset.")
1834 k = find_token(document.body, "status", i + 1, j)
1836 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1839 status = document.body[k]
1840 l = find_default_layout(document, i + 1, j)
1842 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1845 m = find_token(document.body, "\\end_layout", i + 1, j)
1847 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1850 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1851 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1852 if ibox == -1 and pbox == -1:
1853 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1854 del document.body[i+1:k]
1856 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1857 subst1 = [document.body[l],
1858 "\\begin_inset Note Shaded",
1860 '\\begin_layout Standard']
1861 document.body[l:l + 1] = subst1
1862 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1863 document.body[m:m + 1] = subst2
1867 def revert_slash(document):
1868 'Revert \\SpecialChar \\slash{} to ERT'
1870 while i < len(document.body):
1871 m = re.match(r'(.*)\\SpecialChar \\slash{}(.*)', document.body[i])
1876 '\\begin_inset ERT',
1877 'status collapsed', '',
1878 '\\begin_layout Standard',
1879 '', '', '\\backslash',
1884 document.body[i: i+1] = subst
1890 def revert_nobreakdash(document):
1891 'Revert \\SpecialChar \\nobreakdash- to ERT'
1893 while i < len(document.body):
1894 m = re.match(r'(.*)\\SpecialChar \\nobreakdash-(.*)', document.body[i])
1899 '\\begin_inset ERT',
1900 'status collapsed', '',
1901 '\\begin_layout Standard', '', '',
1907 document.body[i: i+1] = subst
1909 j = find_token(document.header, "\\use_amsmath", 0)
1911 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1914 document.header[j] = "\\use_amsmath 2"
1919 #Returns number of lines added/removed
1920 def revert_nocite_key(body, start, end):
1921 'key "..." -> \nocite{...}'
1922 r = re.compile(r'^key "(.*)"')
1926 m = r.match(body[i])
1928 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1929 j += 1 # because we added a line
1930 i += 2 # skip that line
1933 j -= 1 # because we deleted a line
1934 # no need to change i, since it now points to the next line
1938 def revert_nocite(document):
1939 "Revert LatexCommand nocite to ERT"
1942 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1945 if (document.body[i+1] != "LatexCommand nocite"):
1946 # note that we already incremented i
1949 insetEnd = find_end_of_inset(document.body, i)
1951 #this should not happen
1952 document.warning("End of CommandInset citation not found in revert_nocite!")
1955 paramLocation = i + 2 #start of the inset's parameters
1957 document.body[i:i+2] = \
1958 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1959 # that added two lines
1962 #print insetEnd, document.body[i: insetEnd + 1]
1963 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1964 #print insetEnd, document.body[i: insetEnd + 1]
1965 document.body.insert(insetEnd, "\\end_layout")
1966 document.body.insert(insetEnd + 1, "")
1970 def revert_btprintall(document):
1971 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1972 i = find_token(document.header, '\\use_bibtopic', 0)
1974 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1976 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1978 while i < len(document.body):
1979 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1982 j = find_end_of_inset(document.body, i + 1)
1984 #this should not happen
1985 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1986 j = len(document.body)
1987 # this range isn't really right, but it should be OK, since we shouldn't
1988 # see more than one matching line in each inset
1990 for k in range(i, j):
1991 if (document.body[k] == 'btprint "btPrintAll"'):
1992 del document.body[k]
1993 subst = ["\\begin_inset ERT",
1994 "status collapsed", "",
1995 "\\begin_layout Standard", "",
2000 document.body[i:i] = subst
2001 addlines = addedlines + len(subst) - 1
2005 def revert_bahasam(document):
2006 "Set language Bahasa Malaysia to Bahasa Indonesia"
2008 if document.language == "bahasam":
2009 document.language = "bahasa"
2010 i = find_token(document.header, "\\language", 0)
2012 document.header[i] = "\\language bahasa"
2015 j = find_token(document.body, "\\lang bahasam", j)
2018 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
2022 def revert_interlingua(document):
2023 "Set language Interlingua to English"
2025 if document.language == "interlingua":
2026 document.language = "english"
2027 i = find_token(document.header, "\\language", 0)
2029 document.header[i] = "\\language english"
2032 j = find_token(document.body, "\\lang interlingua", j)
2035 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
2039 def revert_serbianlatin(document):
2040 "Set language Serbian-Latin to Croatian"
2042 if document.language == "serbian-latin":
2043 document.language = "croatian"
2044 i = find_token(document.header, "\\language", 0)
2046 document.header[i] = "\\language croatian"
2049 j = find_token(document.body, "\\lang serbian-latin", j)
2052 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
2056 def revert_rotfloat(document):
2057 " Revert sideways custom floats. "
2060 # whitespace intended (exclude \\begin_inset FloatList)
2061 i = find_token(document.body, "\\begin_inset Float ", i)
2064 line = document.body[i]
2065 r = re.compile(r'\\begin_inset Float (.*)$')
2068 document.warning("Unable to match line " + str(i) + " of body!")
2071 floattype = m.group(1)
2072 if floattype == "figure" or floattype == "table":
2075 j = find_end_of_inset(document.body, i)
2077 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
2081 if get_value(document.body, 'sideways', i, j) == "false":
2084 l = find_default_layout(document, i + 1, j)
2086 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2089 subst = ['\\begin_layout Standard',
2090 '\\begin_inset ERT',
2091 'status collapsed', '',
2092 '\\begin_layout Standard', '', '',
2094 'end{sideways' + floattype + '}',
2095 '\\end_layout', '', '\\end_inset']
2096 document.body[j : j+1] = subst
2097 addedLines = len(subst) - 1
2098 del document.body[i+1 : l]
2099 addedLines -= (l-1) - (i+1)
2100 subst = ['\\begin_inset ERT', 'status collapsed', '',
2101 '\\begin_layout Standard', '', '', '\\backslash',
2102 'begin{sideways' + floattype + '}',
2103 '\\end_layout', '', '\\end_inset', '',
2105 document.body[i : i+1] = subst
2106 addedLines += len(subst) - 1
2107 if floattype == "algorithm":
2108 add_to_preamble(document,
2109 ['% Commands inserted by lyx2lyx for sideways algorithm float',
2110 '\\usepackage{rotfloat}',
2111 '\\floatstyle{ruled}',
2112 '\\newfloat{algorithm}{tbp}{loa}',
2113 '\\floatname{algorithm}{Algorithm}'])
2115 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
2119 def revert_widesideways(document):
2120 " Revert wide sideways floats. "
2123 # whitespace intended (exclude \\begin_inset FloatList)
2124 i = find_token(document.body, '\\begin_inset Float ', i)
2127 line = document.body[i]
2128 r = re.compile(r'\\begin_inset Float (.*)$')
2131 document.warning("Unable to match line " + str(i) + " of body!")
2134 floattype = m.group(1)
2135 if floattype != "figure" and floattype != "table":
2138 j = find_end_of_inset(document.body, i)
2140 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2143 if get_value(document.body, 'sideways', i, j) == "false" or \
2144 get_value(document.body, 'wide', i, j) == "false":
2147 l = find_default_layout(document, i + 1, j)
2149 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2152 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2153 'status collapsed', '',
2154 '\\begin_layout Standard', '', '', '\\backslash',
2155 'end{sideways' + floattype + '*}',
2156 '\\end_layout', '', '\\end_inset']
2157 document.body[j : j+1] = subst
2158 addedLines = len(subst) - 1
2159 del document.body[i+1:l-1]
2160 addedLines -= (l-1) - (i+1)
2161 subst = ['\\begin_inset ERT', 'status collapsed', '',
2162 '\\begin_layout Standard', '', '', '\\backslash',
2163 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2164 '\\end_inset', '', '\\end_layout', '']
2165 document.body[i : i+1] = subst
2166 addedLines += len(subst) - 1
2167 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2171 def revert_inset_embedding(document, type):
2172 ' Remove embed tag from certain type of insets'
2175 i = find_token(document.body, "\\begin_inset %s" % type, i)
2178 j = find_end_of_inset(document.body, i)
2180 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2183 k = find_token(document.body, "\tembed", i, j)
2185 k = find_token(document.body, "embed", i, j)
2187 del document.body[k]
2191 def revert_external_embedding(document):
2192 ' Remove embed tag from external inset '
2193 revert_inset_embedding(document, 'External')
2196 def convert_subfig(document):
2197 " Convert subfigures to subfloats. "
2201 i = find_token(document.body, '\\begin_inset Graphics', i)
2204 endInset = find_end_of_inset(document.body, i)
2206 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2209 k = find_token(document.body, '\tsubcaption', i, endInset)
2213 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2217 caption = document.body[l][16:].strip('"')
2218 del document.body[l]
2220 del document.body[k]
2222 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2223 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2224 '', '\\begin_layout Plain Layout'] + latex2lyx(caption, False) + \
2225 [ '\\end_layout', '', '\\end_inset', '',
2226 '\\end_layout', '', '\\begin_layout Plain Layout']
2227 document.body[i : i] = subst
2228 addedLines += len(subst)
2229 endInset += addedLines
2230 subst = ['', '\\end_inset', '', '\\end_layout']
2231 document.body[endInset : endInset] = subst
2232 addedLines += len(subst)
2236 def revert_subfig(document):
2237 " Revert subfloats. "
2240 # whitespace intended (exclude \\begin_inset FloatList)
2241 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2247 j = find_end_of_inset(document.body, i)
2249 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2250 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2252 continue # this will get us back to the outer loop, since j == -1
2253 # look for embedded float (= subfloat)
2254 # whitespace intended (exclude \\begin_inset FloatList)
2255 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2258 # is the subfloat aligned?
2259 al = find_token(document.body, '\\align ', k - 1, j)
2263 if get_value(document.body, '\\align', al) == "center":
2264 alignment_beg = "\\backslash\nbegin{centering}"
2265 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2266 elif get_value(document.body, '\\align', al) == "left":
2267 alignment_beg = "\\backslash\nbegin{raggedright}"
2268 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2269 elif get_value(document.body, '\\align', al) == "right":
2270 alignment_beg = "\\backslash\nbegin{raggedleft}"
2271 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2272 l = find_end_of_inset(document.body, k)
2274 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2277 continue # escape to the outer loop
2278 m = find_default_layout(document, k + 1, l)
2280 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2285 capend = find_end_of_inset(document.body, cap)
2287 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2291 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2293 lblend = find_end_of_inset(document.body, lbl + 1)
2295 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2297 for line in document.body[lbl:lblend + 1]:
2298 if line.startswith('name '):
2299 label = line.split()[1].strip('"')
2306 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2308 optend = find_end_of_inset(document.body, opt)
2310 document.warning("Malformed LyX document: Missing '\\end_inset' (OptArg).")
2312 optc = find_default_layout(document, opt, optend)
2314 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2316 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2317 for line in document.body[optc:optcend]:
2318 if not line.startswith('\\'):
2319 shortcap += line.strip()
2323 for line in document.body[cap:capend]:
2324 if line in document.body[lbl:lblend]:
2326 elif line in document.body[opt:optend]:
2330 caption += lyxline2latex(document, line, inert)
2332 caption += "\n\\backslash\nlabel{" + label + "}"
2333 subst = '\\begin_layout PlainLayout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2334 '\\begin_layout PlainLayout\n\n}' + alignment_end + \
2335 '\n\\end_layout\n\n\\end_inset\n\n' \
2336 '\\end_layout\n\n\\begin_layout PlainLayout\n'
2337 subst = subst.split('\n')
2338 document.body[l : l+1] = subst
2339 addedLines = len(subst) - 1
2340 # this is before l and so is unchanged by the multiline insertion
2342 del document.body[cap:capend+1]
2343 addedLines -= (capend + 1 - cap)
2344 del document.body[k+1:m-1]
2345 addedLines -= (m - 1 - (k + 1))
2346 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2347 '\\begin_layout PlainLayout\n\n' + alignment_beg + '\n\\backslash\n' \
2349 if len(shortcap) > 0:
2350 insertion = insertion + "[" + shortcap + "]"
2351 if len(caption) > 0:
2352 insertion = insertion + "[" + caption + "]"
2353 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2354 insertion = insertion.split('\n')
2355 document.body[k : k + 1] = insertion
2356 addedLines += len(insertion) - 1
2357 al = find_token(document.body, '\\align ', k - 1, j + addedLines)
2359 del document.body[al]
2361 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2365 def revert_wrapplacement(document):
2366 " Revert placement options wrap floats (wrapfig). "
2369 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2372 e = find_end_of_inset(document.body, i)
2373 j = find_token(document.body, "placement", i + 1, e)
2375 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2378 r = re.compile("placement (o|i|l|r|O|I|L|R)")
2379 m = r.match(document.body[j])
2381 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2383 document.body[j] = "placement " + m.group(1).lower()
2387 def remove_extra_embedded_files(document):
2388 " Remove \extra_embedded_files from buffer params "
2389 i = find_token(document.header, '\\extra_embedded_files', 0)
2392 document.header.pop(i)
2395 def convert_spaceinset(document):
2396 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2398 while i < len(document.body):
2399 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2403 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2404 document.body[i: i+1] = subst
2410 def revert_spaceinset(document):
2411 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2414 i = find_token(document.body, "\\begin_inset Space", i)
2417 j = find_end_of_inset(document.body, i)
2419 document.warning("Malformed LyX document: Could not find end of space inset.")
2422 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2423 del document.body[j]
2426 def convert_hfill(document):
2427 " Convert hfill to space inset "
2430 i = find_token(document.body, "\\hfill", i)
2433 subst = document.body[i].replace('\\hfill', \
2434 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2435 subst = subst.split('\n')
2436 document.body[i : i+1] = subst
2440 def revert_hfills(document):
2441 ' Revert \\hfill commands '
2442 hfill = re.compile(r'\\hfill')
2443 dotfill = re.compile(r'\\dotfill')
2444 hrulefill = re.compile(r'\\hrulefill')
2447 i = find_token(document.body, "\\InsetSpace", i)
2450 if hfill.search(document.body[i]):
2451 document.body[i] = \
2452 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2455 if dotfill.search(document.body[i]):
2456 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2457 '\\begin_inset ERT\nstatus collapsed\n\n' \
2458 '\\begin_layout Standard\n\n\n\\backslash\n' \
2459 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2460 subst = subst.split('\n')
2461 document.body[i : i+1] = subst
2464 if hrulefill.search(document.body[i]):
2465 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2466 '\\begin_inset ERT\nstatus collapsed\n\n' \
2467 '\\begin_layout Standard\n\n\n\\backslash\n' \
2468 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2469 subst = subst.split('\n')
2470 document.body[i : i+1] = subst
2475 def revert_hspace(document):
2476 ' Revert \\InsetSpace \\hspace{} to ERT '
2478 hspace = re.compile(r'\\hspace{}')
2479 hstar = re.compile(r'\\hspace\*{}')
2481 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2484 length = get_value(document.body, '\\length', i+1)
2486 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2488 del document.body[i+1]
2490 if hstar.search(document.body[i]):
2491 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2492 '\\begin_inset ERT\nstatus collapsed\n\n' \
2493 '\\begin_layout Standard\n\n\n\\backslash\n' \
2494 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2495 subst = subst.split('\n')
2496 document.body[i : i+1] = subst
2497 addedLines += len(subst) - 1
2500 if hspace.search(document.body[i]):
2501 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2502 '\\begin_inset ERT\nstatus collapsed\n\n' \
2503 '\\begin_layout Standard\n\n\n\\backslash\n' \
2504 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2505 subst = subst.split('\n')
2506 document.body[i : i+1] = subst
2507 addedLines += len(subst) - 1
2513 def revert_protected_hfill(document):
2514 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2517 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2520 j = find_end_of_inset(document.body, i)
2522 document.warning("Malformed LyX document: Could not find end of space inset.")
2525 del document.body[j]
2526 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2527 '\\begin_inset ERT\nstatus collapsed\n\n' \
2528 '\\begin_layout Standard\n\n\n\\backslash\n' \
2529 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2530 subst = subst.split('\n')
2531 document.body[i : i+1] = subst
2535 def revert_leftarrowfill(document):
2536 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2539 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2542 j = find_end_of_inset(document.body, i)
2544 document.warning("Malformed LyX document: Could not find end of space inset.")
2547 del document.body[j]
2548 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2549 '\\begin_inset ERT\nstatus collapsed\n\n' \
2550 '\\begin_layout Standard\n\n\n\\backslash\n' \
2551 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2552 subst = subst.split('\n')
2553 document.body[i : i+1] = subst
2557 def revert_rightarrowfill(document):
2558 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2561 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2564 j = find_end_of_inset(document.body, i)
2566 document.warning("Malformed LyX document: Could not find end of space inset.")
2569 del document.body[j]
2570 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2571 '\\begin_inset ERT\nstatus collapsed\n\n' \
2572 '\\begin_layout Standard\n\n\n\\backslash\n' \
2573 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2574 subst = subst.split('\n')
2575 document.body[i : i+1] = subst
2579 def revert_upbracefill(document):
2580 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2583 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2586 j = find_end_of_inset(document.body, i)
2588 document.warning("Malformed LyX document: Could not find end of space inset.")
2591 del document.body[j]
2592 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2593 '\\begin_inset ERT\nstatus collapsed\n\n' \
2594 '\\begin_layout Standard\n\n\n\\backslash\n' \
2595 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2596 subst = subst.split('\n')
2597 document.body[i : i+1] = subst
2601 def revert_downbracefill(document):
2602 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2605 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2608 j = find_end_of_inset(document.body, i)
2610 document.warning("Malformed LyX document: Could not find end of space inset.")
2613 del document.body[j]
2614 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2615 '\\begin_inset ERT\nstatus collapsed\n\n' \
2616 '\\begin_layout Standard\n\n\n\\backslash\n' \
2617 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2618 subst = subst.split('\n')
2619 document.body[i : i+1] = subst
2623 def revert_local_layout(document):
2624 ' Revert local layout headers.'
2627 i = find_token(document.header, "\\begin_local_layout", i)
2630 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2632 # this should not happen
2634 document.header[i : j + 1] = []
2637 def convert_pagebreaks(document):
2638 ' Convert inline Newpage insets to new format '
2641 i = find_token(document.body, '\\newpage', i)
2644 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2648 i = find_token(document.body, '\\pagebreak', i)
2651 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2655 i = find_token(document.body, '\\clearpage', i)
2658 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2662 i = find_token(document.body, '\\cleardoublepage', i)
2665 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2669 def revert_pagebreaks(document):
2670 ' Revert \\begin_inset Newpage to previous inline format '
2673 i = find_token(document.body, '\\begin_inset Newpage', i)
2676 j = find_end_of_inset(document.body, i)
2678 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2681 del document.body[j]
2682 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2683 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2684 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2685 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2688 def convert_linebreaks(document):
2689 ' Convert inline Newline insets to new format '
2692 i = find_token(document.body, '\\newline', i)
2695 document.body[i:i+1] = ['\\begin_inset Newline newline',
2699 i = find_token(document.body, '\\linebreak', i)
2702 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2706 def revert_linebreaks(document):
2707 ' Revert \\begin_inset Newline to previous inline format '
2710 i = find_token(document.body, '\\begin_inset Newline', i)
2713 j = find_end_of_inset(document.body, i)
2715 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2718 del document.body[j]
2719 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2720 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2723 def convert_japanese_plain(document):
2724 ' Set language japanese-plain to japanese '
2726 if document.language == "japanese-plain":
2727 document.language = "japanese"
2728 i = find_token(document.header, "\\language", 0)
2730 document.header[i] = "\\language japanese"
2733 j = find_token(document.body, "\\lang japanese-plain", j)
2736 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2740 def revert_pdfpages(document):
2741 ' Revert pdfpages external inset to ERT '
2744 i = find_token(document.body, "\\begin_inset External", i)
2747 j = find_end_of_inset(document.body, i)
2749 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2752 if get_value(document.body, 'template', i, j) == "PDFPages":
2753 filename = get_value(document.body, 'filename', i, j)
2755 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2756 for k in range(i, j):
2757 m = r.match(document.body[k])
2760 angle = get_value(document.body, 'rotateAngle', i, j)
2761 width = get_value(document.body, 'width', i, j)
2762 height = get_value(document.body, 'height', i, j)
2763 scale = get_value(document.body, 'scale', i, j)
2764 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2768 options += ",angle=" + angle
2770 options += "angle=" + angle
2773 options += ",width=" + convert_len(width)
2775 options += "width=" + convert_len(width)
2778 options += ",height=" + convert_len(height)
2780 options += "height=" + convert_len(height)
2783 options += ",scale=" + scale
2785 options += "scale=" + scale
2786 if keepAspectRatio != '':
2788 options += ",keepaspectratio"
2790 options += "keepaspectratio"
2792 options = '[' + options + ']'
2793 del document.body[i+1:j+1]
2794 document.body[i:i+1] = ['\\begin_inset ERT',
2797 '\\begin_layout Standard',
2800 'includepdf' + options + '{' + filename + '}',
2804 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2810 def revert_mexican(document):
2811 ' Set language Spanish(Mexico) to Spanish '
2813 if document.language == "spanish-mexico":
2814 document.language = "spanish"
2815 i = find_token(document.header, "\\language", 0)
2817 document.header[i] = "\\language spanish"
2820 j = find_token(document.body, "\\lang spanish-mexico", j)
2823 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2827 def remove_embedding(document):
2828 ' Remove embed tag from all insets '
2829 revert_inset_embedding(document, 'Graphics')
2830 revert_inset_embedding(document, 'External')
2831 revert_inset_embedding(document, 'CommandInset include')
2832 revert_inset_embedding(document, 'CommandInset bibtex')
2835 def revert_master(document):
2836 ' Remove master param '
2837 i = find_token(document.header, "\\master", 0)
2839 del document.header[i]
2842 def revert_graphics_group(document):
2843 ' Revert group information from graphics insets '
2846 i = find_token(document.body, "\\begin_inset Graphics", i)
2849 j = find_end_of_inset(document.body, i)
2851 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2854 k = find_token(document.body, " groupId", i, j)
2858 del document.body[k]
2862 def update_apa_styles(document):
2863 ' Replace obsolete styles '
2865 if document.textclass != "apa":
2868 obsoletedby = { "Acknowledgments": "Acknowledgements",
2869 "Section*": "Section",
2870 "Subsection*": "Subsection",
2871 "Subsubsection*": "Subsubsection",
2872 "Paragraph*": "Paragraph",
2873 "Subparagraph*": "Subparagraph"}
2876 i = find_token(document.body, "\\begin_layout", i)
2880 layout = document.body[i][14:]
2881 if layout in obsoletedby:
2882 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2887 def convert_paper_sizes(document):
2888 ' exchange size options legalpaper and executivepaper to correct order '
2889 # routine is needed to fix http://www.lyx.org/trac/ticket/4868
2892 i = find_token(document.header, "\\papersize executivepaper", 0)
2894 document.header[i] = "\\papersize legalpaper"
2896 j = find_token(document.header, "\\papersize legalpaper", 0)
2898 document.header[j] = "\\papersize executivepaper"
2901 def revert_paper_sizes(document):
2902 ' exchange size options legalpaper and executivepaper to correct order '
2905 i = find_token(document.header, "\\papersize executivepaper", 0)
2907 document.header[i] = "\\papersize legalpaper"
2909 j = find_token(document.header, "\\papersize legalpaper", 0)
2911 document.header[j] = "\\papersize executivepaper"
2914 def convert_InsetSpace(document):
2915 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2918 i = find_token(document.body, "\\begin_inset Space", i)
2921 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2924 def revert_InsetSpace(document):
2925 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2928 i = find_token(document.body, "\\begin_inset space", i)
2931 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2934 def convert_display_enum(document):
2935 " Convert 'display foo' to 'display false/true'"
2938 i = find_token(document.body, "\tdisplay", i)
2941 val = get_value(document.body, 'display', i)
2943 document.body[i] = document.body[i].replace('none', 'false')
2944 if val == "default":
2945 document.body[i] = document.body[i].replace('default', 'true')
2946 if val == "monochrome":
2947 document.body[i] = document.body[i].replace('monochrome', 'true')
2948 if val == "grayscale":
2949 document.body[i] = document.body[i].replace('grayscale', 'true')
2951 document.body[i] = document.body[i].replace('color', 'true')
2952 if val == "preview":
2953 document.body[i] = document.body[i].replace('preview', 'true')
2957 def revert_display_enum(document):
2958 " Revert 'display false/true' to 'display none/color'"
2961 i = find_token(document.body, "\tdisplay", i)
2964 val = get_value(document.body, 'display', i)
2966 document.body[i] = document.body[i].replace('false', 'none')
2968 document.body[i] = document.body[i].replace('true', 'default')
2972 def remove_fontsCJK(document):
2973 ' Remove font_cjk param '
2974 i = find_token(document.header, "\\font_cjk", 0)
2976 del document.header[i]
2979 def convert_plain_layout(document):
2980 " Convert 'PlainLayout' to 'Plain Layout'"
2983 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2986 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2987 '\\begin_layout Plain Layout')
2991 def revert_plain_layout(document):
2992 " Revert 'Plain Layout' to 'PlainLayout'"
2995 i = find_token(document.body, '\\begin_layout Plain Layout', i)
2998 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2999 '\\begin_layout PlainLayout')
3003 def revert_plainlayout(document):
3004 " Revert 'PlainLayout' to 'Standard'"
3007 i = find_token(document.body, '\\begin_layout PlainLayout', i)
3010 # This will be incorrect for some document classes, since Standard is not always
3011 # the default. But (a) it is probably the best we can do and (b) it will actually
3012 # work, in fact, since an unknown layout will be converted to default.
3013 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
3014 '\\begin_layout Standard')
3018 def revert_polytonicgreek(document):
3019 "Set language polytonic Greek to Greek"
3021 if document.language == "polutonikogreek":
3022 document.language = "greek"
3023 i = find_token(document.header, "\\language", 0)
3025 document.header[i] = "\\language greek"
3028 j = find_token(document.body, "\\lang polutonikogreek", j)
3031 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
3035 def revert_removed_modules(document):
3038 i = find_token(document.header, "\\begin_remove_modules", i)
3041 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
3043 # this should not happen
3045 document.header[i : j + 1] = []
3048 def add_plain_layout(document):
3051 i = find_token(document.body, "\\begin_layout", i)
3054 if len(document.body[i].split()) == 1:
3055 document.body[i] = "\\begin_layout Plain Layout"
3059 def revert_tabulators(document):
3060 "Revert tabulators to 4 spaces"
3063 i = find_token(document.body, "\t", i)
3066 document.body[i] = document.body[i].replace("\t", " ")
3070 def revert_tabsize(document):
3071 "Revert the tabsize parameter of listings"
3075 # either it is the only parameter
3076 i = find_token(document.body, 'lstparams "tabsize=4"', i)
3078 del document.body[i]
3080 j = find_token(document.body, "lstparams", j)
3083 pos = document.body[j].find(",tabsize=")
3084 document.body[j] = document.body[j][:pos] + '"'
3089 def revert_mongolian(document):
3090 "Set language Mongolian to English"
3092 if document.language == "mongolian":
3093 document.language = "english"
3094 i = find_token(document.header, "\\language", 0)
3096 document.header[i] = "\\language english"
3099 j = find_token(document.body, "\\lang mongolian", j)
3102 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
3106 def revert_default_options(document):
3107 ' Remove param use_default_options '
3108 i = find_token(document.header, "\\use_default_options", 0)
3110 del document.header[i]
3113 def convert_default_options(document):
3114 ' Add param use_default_options and set it to false '
3115 i = find_token(document.header, "\\textclass", 0)
3117 document.warning("Malformed LyX document: Missing `\\textclass'.")
3119 document.header.insert(i, '\\use_default_options false')
3122 def revert_backref_options(document):
3123 ' Revert option pdf_backref=page to pagebackref '
3124 i = find_token(document.header, "\\pdf_backref page", 0)
3126 document.header[i] = "\\pdf_pagebackref true"
3129 def convert_backref_options(document):
3130 ' We have changed the option pagebackref to backref=true '
3131 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3133 document.header[i] = "\\pdf_backref page"
3134 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3136 del document.header[j]
3137 # backref=true was not a valid option, we meant backref=section
3138 k = find_token(document.header, "\\pdf_backref true", 0)
3139 if k != -1 and i != -1:
3140 del document.header[k]
3141 elif k != -1 and j != -1:
3142 document.header[k] = "\\pdf_backref section"
3145 def convert_charstyle_element(document):
3146 "Convert CharStyle to Element for docbook backend"
3147 if document.backend != "docbook":
3151 i = find_token(document.body, "\\begin_inset Flex CharStyle:", i)
3154 document.body[i] = document.body[i].replace('\\begin_inset Flex CharStyle:',
3155 '\\begin_inset Flex Element:')
3157 def revert_charstyle_element(document):
3158 "Convert Element to CharStyle for docbook backend"
3159 if document.backend != "docbook":
3163 i = find_token(document.body, "\\begin_inset Flex Element:", i)
3166 document.body[i] = document.body[i].replace('\\begin_inset Flex Element:',
3167 '\\begin_inset Flex CharStyle:')
3173 supported_versions = ["1.6.0","1.6"]
3174 convert = [[277, [fix_wrong_tables]],
3175 [278, [close_begin_deeper]],
3176 [279, [long_charstyle_names]],
3177 [280, [axe_show_label]],
3180 [283, [convert_flex]],
3184 [287, [convert_wrapfig_options]],
3185 [288, [convert_inset_command]],
3186 [289, [convert_latexcommand_index]],
3189 [292, [convert_japanese_cjk]],
3191 [294, [convert_pdf_options]],
3192 [295, [convert_htmlurl, convert_url]],
3193 [296, [convert_include]],
3194 [297, [convert_usorbian]],
3195 [298, [convert_macro_global]],
3200 [303, [convert_serbocroatian]],
3201 [304, [convert_framed_notes]],
3208 [311, [convert_ams_classes]],
3210 [313, [convert_module_names]],
3213 [316, [convert_subfig]],
3216 [319, [convert_spaceinset, convert_hfill]],
3218 [321, [convert_tablines]],
3219 [322, [convert_plain_layout]],
3220 [323, [convert_pagebreaks]],
3221 [324, [convert_linebreaks]],
3222 [325, [convert_japanese_plain]],
3225 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3228 [331, [convert_ltcaption]],
3230 [333, [update_apa_styles]],
3231 [334, [convert_paper_sizes]],
3232 [335, [convert_InsetSpace]],
3234 [337, [convert_display_enum]],
3237 [340, [add_plain_layout]],
3240 [343, [convert_default_options]],
3241 [344, [convert_backref_options]],
3242 [345, [convert_charstyle_element]]
3245 revert = [[344, [revert_charstyle_element]],
3246 [343, [revert_backref_options]],
3247 [342, [revert_default_options]],
3248 [341, [revert_mongolian]],
3249 [340, [revert_tabulators, revert_tabsize]],
3251 [338, [revert_removed_modules]],
3252 [337, [revert_polytonicgreek]],
3253 [336, [revert_display_enum]],
3254 [335, [remove_fontsCJK]],
3255 [334, [revert_InsetSpace]],
3256 [333, [revert_paper_sizes]],
3258 [331, [revert_graphics_group]],
3259 [330, [revert_ltcaption]],
3260 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
3261 [328, [revert_master]],
3263 [326, [revert_mexican]],
3264 [325, [revert_pdfpages]],
3266 [323, [revert_linebreaks]],
3267 [322, [revert_pagebreaks]],
3268 [321, [revert_local_layout, revert_plain_layout]],
3269 [320, [revert_tablines]],
3270 [319, [revert_protected_hfill]],
3271 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3272 [317, [remove_extra_embedded_files]],
3273 [316, [revert_wrapplacement]],
3274 [315, [revert_subfig]],
3275 [314, [revert_colsep, revert_plainlayout]],
3277 [312, [revert_module_names]],
3278 [311, [revert_rotfloat, revert_widesideways]],
3279 [310, [revert_external_embedding]],
3280 [309, [revert_btprintall]],
3281 [308, [revert_nocite]],
3282 [307, [revert_serbianlatin]],
3283 [306, [revert_slash, revert_nobreakdash]],
3284 [305, [revert_interlingua]],
3285 [304, [revert_bahasam]],
3286 [303, [revert_framed_notes]],
3288 [301, [revert_latin, revert_samin]],
3289 [300, [revert_linebreak]],
3290 [299, [revert_pagebreak]],
3291 [298, [revert_hyperlinktype]],
3292 [297, [revert_macro_optional_params]],
3293 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3294 [295, [revert_include]],
3295 [294, [revert_href, revert_url]],
3296 [293, [revert_pdf_options_2]],
3297 [292, [revert_inset_info]],
3298 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3299 [290, [revert_vietnamese]],
3300 [289, [revert_wraptable]],
3301 [288, [revert_latexcommand_index]],
3302 [287, [revert_inset_command]],
3303 [286, [revert_wrapfig_options]],
3304 [285, [revert_pdf_options]],
3305 [284, [remove_inzip_options]],
3307 [282, [revert_flex]],
3309 [280, [revert_begin_modules]],
3310 [279, [revert_show_label]],
3311 [278, [revert_long_charstyle_names]],
3317 if __name__ == "__main__":