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 ####################################################################
28 # Private helper functions
31 def get_value_string(lines, token, start, end = 0, trim = False, default = ""):
32 """ get_value_string(lines, token, start[[, end], trim, default]) -> string
34 Return tokens after token as string, in lines, where
35 token is the first element. When trim is used, the first and last character
36 of the string is trimmed."""
38 val = get_value(lines, token, start, end, "")
46 def find_end_of_inset(lines, i):
47 " Find end of inset, where lines[i] is included."
48 return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
52 # document.body[i] = wrap_insert_ert(...)
53 # wrap_into_ert may returns a multiline string, which should NOT appear
54 # in document.body. Instead, do something like this:
55 # subst = wrap_inset_ert(...)
56 # subst = subst.split('\n')
57 # document.body[i:i+1] = subst
59 # where the last statement resets the counter to accord with the added
61 def wrap_into_ert(string, src, dst):
62 '''Within string, replace occurrences of src with dst, wrapped into ERT
63 E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is:
64 sch<ERT>\\backslash</ERT>"on'''
65 return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
66 + dst + '\n\\end_layout\n\\end_inset\n')
68 def put_cmd_in_ert(string):
69 for rep in unicode_reps:
70 string = string.replace(rep[1], rep[0].replace('\\\\', '\\'))
71 string = string.replace('\\', "\\backslash\n")
72 string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n" \
73 + string + "\n\\end_layout\n\\end_inset"
76 def add_to_preamble(document, text):
77 """ Add text to the preamble if it is not already there.
78 Only the first line is checked!"""
80 if find_token(document.preamble, text[0], 0) != -1:
83 document.preamble.extend(text)
85 def insert_to_preamble(index, document, text):
86 """ Insert text to the preamble at a given line"""
88 document.preamble.insert(index, text)
90 # Convert a LyX length into a LaTeX length
92 units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
93 "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
94 "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
96 # Convert LyX units to LaTeX units
97 for unit in list(units.keys()):
98 if len.find(unit) != -1:
99 len = '%f' % (len2value(len) / 100)
100 len = len.strip('0') + units[unit]
105 # Return the value of len without the unit in numerical form.
107 result = re.search('([+-]?[0-9.]+)', len)
109 return float(result.group(1))
110 # No number means 1.0
113 # Unfortunately, this doesn't really work, since Standard isn't always default.
114 # But it's as good as we can do right now.
115 def find_default_layout(document, start, end):
116 l = find_token(document.body, "\\begin_layout Standard", start, end)
118 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
120 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
123 def get_option(document, m, option, default):
124 l = document.body[m].find(option)
127 val = document.body[m][l:].split('"')[1]
130 def remove_option(document, m, option):
131 l = document.body[m].find(option)
133 val = document.body[m][l:].split('"')[1]
134 document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
137 def set_option(document, m, option, value):
138 l = document.body[m].find(option)
140 oldval = document.body[m][l:].split('"')[1]
141 l = l + len(option + '="')
142 document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
144 document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
148 # FIXME: Use the version in unicode_symbols.py which has some bug fixes
149 def read_unicodesymbols():
150 " Read the unicodesymbols list of unicode characters and corresponding commands."
151 pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
152 fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
154 # Two backslashes, followed by some non-word character, and then a character
155 # in brackets. The idea is to check for constructs like: \"{u}, which is how
156 # they are written in the unicodesymbols file; but they can also be written
157 # as: \"u or even \" u.
158 r = re.compile(r'\\\\(\W)\{(\w)\}')
159 for line in fp.readlines():
160 if line[0] != '#' and line.strip() != "":
161 line=line.replace(' "',' ') # remove all quotation marks with spaces before
162 line=line.replace('" ',' ') # remove all quotation marks with spaces after
163 line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
165 [ucs4,command,dead] = line.split(None,2)
166 if command[0:1] != "\\":
168 spec_chars.append([command, unichr(eval(ucs4))])
174 # If the character is a double-quote, then we need to escape it, too,
175 # since it is done that way in the LyX file.
176 if m.group(1) == "\"":
179 command += m.group(1) + m.group(2)
180 commandbl += m.group(1) + ' ' + m.group(2)
181 spec_chars.append([command, unichr(eval(ucs4))])
182 spec_chars.append([commandbl, unichr(eval(ucs4))])
187 def extract_argument(line):
188 'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
193 bracere = re.compile("(\s*)(.*)")
194 n = bracere.match(line)
195 whitespace = n.group(1)
198 if brace != "[" and brace != "{":
222 # We never found the matching brace
223 # So, to be on the safe side, let's just return everything
224 # which will then get wrapped as ERT
226 return (line[:pos + 1], line[pos + 1:])
229 def latex2ert(line, isindex):
230 '''Converts LaTeX commands into ERT. line may well be a multi-line
231 string when it is returned.'''
236 ## FIXME Escaped \ ??
237 # This regex looks for a LaTeX command---i.e., something of the form
238 # "\alPhaStuFF", or "\X", where X is any character---where the command
239 # may also be preceded by an additional backslash, which is how it would
240 # appear (e.g.) in an InsetIndex.
241 labelre = re.compile(r'(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)')
243 m = labelre.match(line)
250 (arg, rest) = extract_argument(end)
255 # If we wanted to put labels into an InsetLabel, for example, then we
256 # would just need to test here for cmd == "label" and then take some
257 # appropriate action, i.e., to use arg to get the content and then
258 # wrap it appropriately.
259 cmd = put_cmd_in_ert(cmd)
260 retval += "\n" + cmd + "\n"
262 m = labelre.match(line)
263 # put all remaining braces in ERT
264 line = wrap_into_ert(line, '}', '}')
265 line = wrap_into_ert(line, '{', '{')
267 # active character that is not available in all font encodings
268 line = wrap_into_ert(line, '|', '|')
273 unicode_reps = read_unicodesymbols()
276 #Might should do latex2ert first, then deal with stuff that DOESN'T
277 #end up inside ERT. That routine could be modified so that it returned
278 #a list of lines, and we could then skip ERT bits and only deal with
280 def latex2lyx(data, isindex):
281 '''Takes a string, possibly multi-line, and returns the result of
282 converting LaTeX constructs into LyX constructs. Returns a list of
283 lines, suitable for insertion into document.body.
284 The bool isindex specifies whether we are in an index macro (which
285 has some specific active characters that need to be ERTed).'''
291 # Convert LaTeX to Unicode
292 # Commands of this sort need to be checked to make sure they are
293 # followed by a non-alpha character, lest we replace too much.
294 hardone = re.compile(r'^\\\\[a-zA-Z]+$')
296 for rep in unicode_reps:
297 if hardone.match(rep[0]):
300 pos = data.find(rep[0], pos)
303 nextpos = pos + len(rep[0])
304 if nextpos < len(data) and data[nextpos].isalpha():
305 # not the end of that command
308 data = data[:pos] + rep[1] + data[nextpos:]
311 data = data.replace(rep[0], rep[1])
315 data = wrap_into_ert(data, r'\"', '"')
317 data = data.replace('\\\\', '\\')
320 mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
321 lines = data.split('\n')
323 #document.warning("LINE: " + line)
324 #document.warning(str(i) + ":" + document.body[i])
325 #document.warning("LAST: " + document.body[-1])
330 f = m.group(2).replace('\\\\', '\\')
334 s = latex2ert(s, isindex)
335 subst = s.split('\n')
337 retval.append("\\begin_inset Formula " + f)
338 retval.append("\\end_inset")
340 # Handle whatever is left, which is just text
341 g = latex2ert(g, isindex)
342 subst = g.split('\n')
347 def lyxline2latex(document, line, inert):
348 'Convert some LyX stuff into corresponding LaTeX stuff line-wise, as best we can.'
349 if line.startswith("\\begin_inset Formula"):
351 elif line.startswith("\\begin_inset Quotes"):
352 # For now, we do a very basic reversion. Someone who understands
353 # quotes is welcome to fix it up.
354 qtype = line[20:].strip()
368 elif line.isspace() or \
369 line.startswith("\\begin_layout") or \
370 line.startswith("\\end_layout") or \
371 line.startswith("\\begin_inset") or \
372 line.startswith("\\end_inset") or \
373 line.startswith("\\lang") or \
374 line.strip() == "status collapsed" or \
375 line.strip() == "status open":
379 # this needs to be added to the preamble because of cases like
380 # \textmu, \textbackslash, etc.
381 add_to_preamble(document, ['% added by lyx2lyx for converted entries',
382 '\\@ifundefined{textmu}',
383 ' {\\usepackage{textcomp}}{}'])
384 # a lossless reversion is not possible
385 # try at least to handle some common insets and settings
387 line = line.replace(r'\backslash', '\\')
389 line = line.replace('&', '\\&{}')
390 line = line.replace('#', '\\#{}')
391 line = line.replace('^', '\\^{}')
392 line = line.replace('%', '\\%{}')
393 line = line.replace('_', '\\_{}')
394 line = line.replace('$', '\\${}')
396 # Do the LyX text --> LaTeX conversion
397 for rep in unicode_reps:
398 line = line.replace(rep[1], rep[0].replace('\\\\', '\\') + "{}")
399 line = line.replace(r'\backslash', r'\textbackslash{}')
400 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
401 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
402 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
403 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
404 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
405 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
406 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
407 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
408 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
412 def lyx2latex(document, lines):
413 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
414 # clean up multiline stuff
418 for curline in range(len(lines)):
419 line = lines[curline]
420 if line.startswith("\\begin_inset ERT"):
421 # We don't want to replace things inside ERT, so figure out
422 # where the end of the inset is.
423 ert_end = find_end_of_inset(lines, curline + 1)
425 inert = ert_end >= curline
426 content += lyxline2latex(document, lines[curline], inert)
431 ####################################################################
433 def convert_ltcaption(document):
436 i = find_token(document.body, "\\begin_inset Tabular", i)
439 j = find_end_of_inset(document.body, i + 1)
441 document.warning("Malformed LyX document: Could not find end of tabular.")
445 nrows = int(document.body[i+1].split('"')[3])
446 ncols = int(document.body[i+1].split('"')[5])
449 for k in range(nrows):
450 m = find_token(document.body, "<row", m)
453 for k in range(ncols):
454 m = find_token(document.body, "<cell", m)
456 mend = find_token(document.body, "</cell>", m + 1)
457 # first look for caption insets
458 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
459 # then look for ERT captions
461 mcap = find_token(document.body, "caption", m + 1, mend)
463 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
466 if caption == 'true':
468 set_option(document, r, 'caption', 'true')
469 set_option(document, m, 'multicolumn', '1')
470 set_option(document, m, 'bottomline', 'false')
471 set_option(document, m, 'topline', 'false')
472 set_option(document, m, 'rightline', 'false')
473 set_option(document, m, 'leftline', 'false')
474 #j = find_end_of_inset(document.body, j + 1)
476 set_option(document, m, 'multicolumn', '2')
483 #FIXME Use of wrap_into_ert can confuse lyx2lyx
484 def revert_ltcaption(document):
487 i = find_token(document.body, "\\begin_inset Tabular", i)
490 j = find_end_of_inset(document.body, i + 1)
492 document.warning("Malformed LyX document: Could not find end of tabular.")
497 nrows = int(document.body[i+1].split('"')[3])
498 ncols = int(document.body[i+1].split('"')[5])
500 for k in range(nrows):
501 m = find_token(document.body, "<row", m)
502 caption = get_option(document, m, 'caption', 'false')
503 if caption == 'true':
504 remove_option(document, m, 'caption')
505 for k in range(ncols):
506 m = find_token(document.body, "<cell", m)
507 remove_option(document, m, 'multicolumn')
509 m = find_token(document.body, "\\begin_inset Caption", m)
512 m = find_end_of_inset(document.body, m + 1)
513 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
519 def convert_tablines(document):
522 i = find_token(document.body, "\\begin_inset Tabular", i)
524 # LyX 1.3 inserted an extra space between \begin_inset
525 # and Tabular so let us try if this is the case and fix it.
526 i = find_token(document.body, "\\begin_inset Tabular", i)
530 document.body[i] = "\\begin_inset Tabular"
531 j = find_end_of_inset(document.body, i + 1)
533 document.warning("Malformed LyX document: Could not find end of tabular.")
538 nrows = int(document.body[i+1].split('"')[3])
539 ncols = int(document.body[i+1].split('"')[5])
542 for k in range(ncols):
543 m = find_token(document.body, "<column", m)
544 left = get_option(document, m, 'leftline', 'false')
545 right = get_option(document, m, 'rightline', 'false')
546 col_info.append([left, right])
547 remove_option(document, m, 'leftline')
548 remove_option(document, m, 'rightline')
552 for k in range(nrows):
553 m = find_token(document.body, "<row", m)
554 top = get_option(document, m, 'topline', 'false')
555 bottom = get_option(document, m, 'bottomline', 'false')
556 row_info.append([top, bottom])
557 remove_option(document, m, 'topline')
558 remove_option(document, m, 'bottomline')
563 for k in range(nrows*ncols):
564 m = find_token(document.body, "<cell", m)
565 mc_info.append(get_option(document, m, 'multicolumn', '0'))
568 for l in range(nrows):
569 for k in range(ncols):
570 m = find_token(document.body, '<cell', m)
571 if mc_info[l*ncols + k] == '0':
572 r = set_option(document, m, 'topline', row_info[l][0])
573 r = set_option(document, m, 'bottomline', row_info[l][1])
574 r = set_option(document, m, 'leftline', col_info[k][0])
575 r = set_option(document, m, 'rightline', col_info[k][1])
576 elif mc_info[l*ncols + k] == '1':
578 while s < ncols and mc_info[l*ncols + s] == '2':
580 if s < ncols and mc_info[l*ncols + s] != '1':
581 r = set_option(document, m, 'rightline', col_info[k][1])
582 if k > 0 and mc_info[l*ncols + k - 1] == '0':
583 r = set_option(document, m, 'leftline', col_info[k][0])
588 def revert_tablines(document):
591 i = find_token(document.body, "\\begin_inset Tabular", i)
594 j = find_end_of_inset(document.body, i)
596 document.warning("Malformed LyX document: Could not find end of tabular.")
601 nrows = int(document.body[i+1].split('"')[3])
602 ncols = int(document.body[i+1].split('"')[5])
605 for k in range(nrows*ncols):
606 m = find_token(document.body, "<cell", m)
607 top = get_option(document, m, 'topline', 'false')
608 bottom = get_option(document, m, 'bottomline', 'false')
609 left = get_option(document, m, 'leftline', 'false')
610 right = get_option(document, m, 'rightline', 'false')
611 lines.append([top, bottom, left, right])
614 # we will want to ignore longtable captions
617 for k in range(nrows):
618 m = find_token(document.body, "<row", m)
619 caption = get_option(document, m, 'caption', 'false')
620 caption_info.append([caption])
625 for k in range(ncols):
626 m = find_token(document.body, "<column", m)
628 for l in range(nrows):
629 left = lines[l*ncols + k][2]
630 if left == 'false' and caption_info[l] == 'false':
632 set_option(document, m, 'leftline', left)
634 for l in range(nrows):
635 right = lines[l*ncols + k][3]
636 if right == 'false' and caption_info[l] == 'false':
638 set_option(document, m, 'rightline', right)
642 for k in range(nrows):
643 m = find_token(document.body, "<row", m)
645 for l in range(ncols):
646 top = lines[k*ncols + l][0]
649 if caption_info[k] == 'false':
651 set_option(document, m, 'topline', top)
653 for l in range(ncols):
654 bottom = lines[k*ncols + l][1]
655 if bottom == 'false':
657 if caption_info[k] == 'false':
659 set_option(document, m, 'bottomline', bottom)
665 def fix_wrong_tables(document):
668 i = find_token(document.body, "\\begin_inset Tabular", i)
671 j = find_end_of_inset(document.body, i + 1)
673 document.warning("Malformed LyX document: Could not find end of tabular.")
678 nrows = int(document.body[i+1].split('"')[3])
679 ncols = int(document.body[i+1].split('"')[5])
681 for l in range(nrows):
683 for k in range(ncols):
684 m = find_token(document.body, '<cell', m)
686 if document.body[m].find('multicolumn') != -1:
687 multicol_cont = int(document.body[m].split('"')[1])
689 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
690 document.body[m] = document.body[m][:5] + document.body[m][21:]
693 prev_multicolumn = multicol_cont
700 def close_begin_deeper(document):
704 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
709 if document.body[i][:13] == "\\begin_deeper":
716 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
719 def long_charstyle_names(document):
722 i = find_token(document.body, "\\begin_inset CharStyle", i)
725 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
728 def revert_long_charstyle_names(document):
731 i = find_token(document.body, "\\begin_inset CharStyle", i)
734 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
738 def axe_show_label(document):
741 i = find_token(document.body, "\\begin_inset CharStyle", i)
744 if document.body[i + 1].find("show_label") != -1:
745 if document.body[i + 1].find("true") != -1:
746 document.body[i + 1] = "status open"
747 del document.body[ i + 2]
749 if document.body[i + 1].find("false") != -1:
750 document.body[i + 1] = "status collapsed"
751 del document.body[ i + 2]
753 document.warning("Malformed LyX document: show_label neither false nor true.")
755 document.warning("Malformed LyX document: show_label missing in CharStyle.")
760 def revert_show_label(document):
763 i = find_token(document.body, "\\begin_inset CharStyle", i)
766 if document.body[i + 1].find("status open") != -1:
767 document.body.insert(i + 1, "show_label true")
769 if document.body[i + 1].find("status collapsed") != -1:
770 document.body.insert(i + 1, "show_label false")
772 document.warning("Malformed LyX document: no legal status line in CharStyle.")
775 def revert_begin_modules(document):
778 i = find_token(document.header, "\\begin_modules", i)
781 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
783 # this should not happen
785 document.header[i : j + 1] = []
787 def convert_flex(document):
788 "Convert CharStyle to Flex"
791 i = find_token(document.body, "\\begin_inset CharStyle", i)
794 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
796 def revert_flex(document):
797 "Revert Flex to CharStyle"
800 i = find_token(document.body, "\\begin_inset Flex", i)
803 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
806 def revert_pdf_options(document):
807 "Revert PDF options for hyperref."
808 # store the PDF options and delete the entries from the Lyx file
816 bookmarksnumbered = ""
818 bookmarksopenlevel = ""
826 i = find_token(document.header, "\\use_hyperref", i)
828 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
829 del document.header[i]
830 i = find_token(document.header, "\\pdf_store_options", i)
832 del document.header[i]
833 i = find_token(document.header, "\\pdf_title", 0)
835 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
836 title = ' pdftitle={' + title + '}'
837 del document.header[i]
838 i = find_token(document.header, "\\pdf_author", 0)
840 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
842 author = ' pdfauthor={' + author + '}'
844 author = ',\n pdfauthor={' + author + '}'
845 del document.header[i]
846 i = find_token(document.header, "\\pdf_subject", 0)
848 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
849 if title == "" and author == "":
850 subject = ' pdfsubject={' + subject + '}'
852 subject = ',\n pdfsubject={' + subject + '}'
853 del document.header[i]
854 i = find_token(document.header, "\\pdf_keywords", 0)
856 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
857 if title == "" and author == "" and subject == "":
858 keywords = ' pdfkeywords={' + keywords + '}'
860 keywords = ',\n pdfkeywords={' + keywords + '}'
861 del document.header[i]
862 i = find_token(document.header, "\\pdf_bookmarks", 0)
864 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
865 bookmarks = ',\n bookmarks=' + bookmarks
866 del document.header[i]
867 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
869 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
870 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
871 del document.header[i]
872 i = find_token(document.header, "\\pdf_bookmarksopen", i)
874 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
875 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
876 del document.header[i]
877 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
879 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
880 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
881 del document.header[i]
882 i = find_token(document.header, "\\pdf_breaklinks", i)
884 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
885 breaklinks = ',\n breaklinks=' + breaklinks
886 del document.header[i]
887 i = find_token(document.header, "\\pdf_pdfborder", i)
889 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
890 if pdfborder == 'true':
891 pdfborder = ',\n pdfborder={0 0 0}'
893 pdfborder = ',\n pdfborder={0 0 1}'
894 del document.header[i]
895 i = find_token(document.header, "\\pdf_colorlinks", i)
897 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
898 colorlinks = ',\n colorlinks=' + colorlinks
899 del document.header[i]
900 i = find_token(document.header, "\\pdf_backref", i)
902 backref = get_value_string(document.header, '\\pdf_backref', 0)
903 backref = ',\n backref=' + backref
904 del document.header[i]
905 i = find_token(document.header, "\\pdf_pagebackref", i)
907 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
908 pagebackref = ',\n pagebackref=' + pagebackref
909 del document.header[i]
910 i = find_token(document.header, "\\pdf_pagemode", 0)
912 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
913 pagemode = ',\n pdfpagemode=' + pagemode
914 del document.header[i]
915 i = find_token(document.header, "\\pdf_quoted_options", 0)
917 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
918 if title == "" and author == "" and subject == "" and keywords == "":
919 otheroptions = ' ' + otheroptions
921 otheroptions = ',\n ' + otheroptions
922 del document.header[i]
924 # write to the preamble when hyperref was used
926 # preamble write preparations
927 # bookmark numbers are only output when they are turned on
928 if bookmarksopen == ',\n bookmarksopen=true':
929 bookmarksopen = bookmarksopen + bookmarksopenlevel
930 if bookmarks == ',\n bookmarks=true':
931 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
933 bookmarks = bookmarks
934 # hypersetup is only output when there are things to be set up
935 setupstart = '\\hypersetup{%\n'
937 if otheroptions == "" and title == "" and author == ""\
938 and subject == "" and keywords == "":
942 # babel must be loaded before hyperref and hyperref the first part
943 # of the preamble, like in LyX 1.6
944 insert_to_preamble(0, document,
945 '% Commands inserted by lyx2lyx for PDF properties\n'
946 + '\\usepackage{babel}\n'
947 + '\\usepackage[unicode=true'
966 def remove_inzip_options(document):
967 "Remove inzipName and embed options from the Graphics inset"
970 i = find_token(document.body, "\\begin_inset Graphics", i)
973 j = find_end_of_inset(document.body, i + 1)
976 document.warning("Malformed LyX document: Could not find end of graphics inset.")
979 # If there's a inzip param, just remove that
980 k = find_token(document.body, "\tinzipName", i + 1, j)
983 # embed option must follow the inzipName option
984 del document.body[k+1]
988 def convert_inset_command(document):
991 \begin_inset LatexCommand cmd
993 \begin_inset CommandInset InsetType
998 i = find_token(document.body, "\\begin_inset LatexCommand", i)
1001 line = document.body[i]
1002 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
1004 cmdName = m.group(1)
1006 #this is adapted from factory.cpp
1007 if cmdName[0:4].lower() == "cite":
1008 insetName = "citation"
1009 elif cmdName == "url" or cmdName == "htmlurl":
1011 elif cmdName[-3:] == "ref":
1013 elif cmdName == "tableofcontents":
1015 elif cmdName == "printnomenclature":
1016 insetName = "nomencl_print"
1017 elif cmdName == "printindex":
1018 insetName = "index_print"
1021 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
1022 document.body[i : i+1] = insertion
1025 def revert_inset_command(document):
1028 \begin_inset CommandInset InsetType
1031 \begin_inset LatexCommand cmd
1032 Some insets may end up being converted to insets earlier versions of LyX
1033 will not be able to recognize. Not sure what to do about that.
1037 i = find_token(document.body, "\\begin_inset CommandInset", i)
1040 nextline = document.body[i+1]
1041 r = re.compile(r'LatexCommand\s+(.*)$')
1042 m = r.match(nextline)
1044 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
1047 cmdName = m.group(1)
1048 insertion = ["\\begin_inset LatexCommand " + cmdName]
1049 document.body[i : i+2] = insertion
1052 def convert_wrapfig_options(document):
1053 "Convert optional options for wrap floats (wrapfig)."
1054 # adds the tokens "lines", "placement", and "overhang"
1057 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1060 document.body.insert(i + 1, "lines 0")
1061 j = find_token(document.body, "placement", i)
1062 # placement can be already set or not; if not, set it
1064 document.body.insert(i + 3, "overhang 0col%")
1066 document.body.insert(i + 2, "placement o")
1067 document.body.insert(i + 3, "overhang 0col%")
1071 def revert_wrapfig_options(document):
1072 "Revert optional options for wrap floats (wrapfig)."
1075 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1078 j = find_end_of_inset(document.body, i)
1080 document.warning("Can't find end of Wrap inset at line " + str(i))
1083 k = find_default_layout(document, i, j)
1085 document.warning("Can't find default layout for Wrap figure!")
1088 # Options should be between i and k now
1089 l = find_token(document.body, "lines", i, k)
1091 document.warning("Can't find lines option for Wrap figure!")
1094 m = find_token(document.body, "overhang", i + 1, k)
1096 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1099 # Do these in reverse order
1100 del document.body[m]
1101 del document.body[l]
1105 def convert_latexcommand_index(document):
1106 "Convert from LatexCommand form to collapsable form."
1108 r1 = re.compile('name "(.*)"')
1110 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1113 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1116 j = find_end_of_inset(document.body, i + 1)
1118 document.warning("Unable to find end of index inset at line " + str(i) + "!")
1121 m = r1.match(document.body[i + 2])
1123 document.warning("Unable to match: " + document.body[i+2])
1124 # this can happen with empty index insets!
1127 fullcontent = m.group(1)
1128 linelist = latex2lyx(fullcontent, True)
1129 #document.warning(fullcontent)
1131 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1132 linelist + ["\\end_layout"]
1133 document.body[i : j] = linelist
1134 i += len(linelist) - (j - i)
1137 def revert_latexcommand_index(document):
1138 "Revert from collapsable form to LatexCommand form."
1141 i = find_token(document.body, "\\begin_inset Index", i)
1144 j = find_end_of_inset(document.body, i + 1)
1148 content = lyx2latex(document, document.body[i:j])
1150 content = content.replace('"', r'\"')
1151 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1152 "name " + '"' + content + '"', ""]
1156 def revert_wraptable(document):
1157 "Revert wrap table to wrap figure."
1160 i = find_token(document.body, "\\begin_inset Wrap table", i)
1163 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1167 def revert_vietnamese(document):
1168 "Set language Vietnamese to English"
1169 # Set document language from Vietnamese to English
1171 if document.language == "vietnamese":
1172 document.language = "english"
1173 i = find_token(document.header, "\\language", 0)
1175 document.header[i] = "\\language english"
1178 j = find_token(document.body, "\\lang vietnamese", j)
1181 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1185 def convert_japanese_cjk(document):
1186 "Set language japanese to japanese-cjk"
1187 # Set document language from japanese-plain to japanese
1189 if document.language == "japanese":
1190 document.language = "japanese-cjk"
1191 i = find_token(document.header, "\\language", 0)
1193 document.header[i] = "\\language japanese-cjk"
1196 j = find_token(document.body, "\\lang japanese", j)
1199 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1203 def revert_japanese(document):
1204 "Set language japanese-plain to japanese"
1205 # Set document language from japanese-plain to japanese
1207 if document.language == "japanese-plain":
1208 document.language = "japanese"
1209 i = find_token(document.header, "\\language", 0)
1211 document.header[i] = "\\language japanese"
1214 j = find_token(document.body, "\\lang japanese-plain", j)
1217 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1221 def revert_japanese_cjk(document):
1222 "Set language japanese-cjk to japanese"
1223 # Set document language from japanese-plain to japanese
1225 if document.language == "japanese-cjk":
1226 document.language = "japanese"
1227 i = find_token(document.header, "\\language", 0)
1229 document.header[i] = "\\language japanese"
1232 j = find_token(document.body, "\\lang japanese-cjk", j)
1235 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1239 def revert_japanese_encoding(document):
1240 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1241 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1243 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1245 document.header[i] = "\\inputencoding EUC-JP"
1247 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1249 document.header[j] = "\\inputencoding JIS"
1251 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1252 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1253 document.header[k] = "\\inputencoding UTF8"
1256 def revert_inset_info(document):
1257 'Replace info inset with its content'
1260 i = find_token(document.body, '\\begin_inset Info', i)
1263 j = find_end_of_inset(document.body, i + 1)
1266 document.warning("Malformed LyX document: Could not find end of Info inset.")
1271 for k in range(i, j+1):
1272 if document.body[k].startswith("arg"):
1273 arg = document.body[k][3:].strip()
1274 # remove embracing quotation marks
1277 if arg[len(arg) - 1] == '"':
1278 arg = arg[:len(arg) - 1]
1279 # \" to straight quote
1280 arg = arg.replace(r'\"', '"')
1282 arg = arg.replace(r'\\', "\\backslash\n")
1283 if document.body[k].startswith("type"):
1284 type = document.body[k][4:].strip().strip('"')
1285 # I think there is a newline after \\end_inset, which should be removed.
1286 if document.body[j + 1].strip() == "":
1287 document.body[i : (j + 2)] = [type + ':' + arg]
1289 document.body[i : (j + 1)] = [type + ':' + arg]
1292 def convert_pdf_options(document):
1293 # Set the pdfusetitle tag, delete the pdf_store_options,
1294 # set quotes for bookmarksopenlevel"
1295 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1297 k = find_token(document.header, "\\use_hyperref", 0)
1298 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1299 k = find_token(document.header, "\\pdf_store_options", 0)
1301 del document.header[k]
1302 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1304 document.header[i] = document.header[i].replace('"', '')
1307 def revert_pdf_options_2(document):
1308 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1309 k = find_token(document.header, "\\use_hyperref", 0)
1310 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1312 del document.header[i]
1313 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1315 values = document.header[i].split()
1316 values[1] = ' "' + values[1] + '"'
1317 document.header[i] = ''.join(values)
1320 def convert_htmlurl(document):
1321 'Convert "htmlurl" to "href" insets for docbook'
1322 if document.backend != "docbook":
1326 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1329 document.body[i] = "\\begin_inset CommandInset href"
1330 document.body[i + 1] = "LatexCommand href"
1334 def convert_url(document):
1335 'Convert url insets to url charstyles'
1336 if document.backend == "docbook":
1340 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1343 n = find_token(document.body, "name", i)
1345 # place the URL name in typewriter before the new URL insert
1346 # grab the name 'bla' from the e.g. the line 'name "bla"',
1347 # therefore start with the 6th character
1348 name = document.body[n][6:-1]
1349 newname = [name + " "]
1350 document.body[i:i] = newname
1352 j = find_token(document.body, "target", i)
1354 document.warning("Malformed LyX document: Can't find target for url inset")
1357 target = document.body[j][8:-1]
1358 k = find_token(document.body, "\\end_inset", j)
1360 document.warning("Malformed LyX document: Can't find end of url inset")
1363 newstuff = ["\\begin_inset Flex URL",
1364 "status collapsed", "",
1365 "\\begin_layout Standard",
1370 document.body[i:k] = newstuff
1371 i = i + len(newstuff)
1373 def convert_ams_classes(document):
1374 tc = document.textclass
1375 if (tc != "amsart" and tc != "amsart-plain" and
1376 tc != "amsart-seq" and tc != "amsbook"):
1378 if tc == "amsart-plain":
1379 document.textclass = "amsart"
1380 document.set_textclass()
1381 document.add_module("Theorems (Starred)")
1383 if tc == "amsart-seq":
1384 document.textclass = "amsart"
1385 document.set_textclass()
1386 document.add_module("Theorems (AMS)")
1388 #Now we want to see if any of the environments in the extended theorems
1389 #module were used in this document. If so, we'll add that module, too.
1390 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1391 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1394 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1397 i = find_token(document.body, "\\begin_layout", i)
1400 m = r.match(document.body[i])
1402 # This is an empty layout
1403 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1407 if layouts.count(m) != 0:
1408 document.add_module("Theorems (AMS-Extended)")
1412 def revert_href(document):
1413 'Reverts hyperlink insets (href) to url insets (url)'
1416 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1419 document.body[i : i + 2] = \
1420 ["\\begin_inset CommandInset url", "LatexCommand url"]
1423 def revert_url(document):
1424 'Reverts Flex URL insets to old-style URL insets'
1427 i = find_token(document.body, "\\begin_inset Flex URL", i)
1430 j = find_end_of_inset(document.body, i)
1432 document.warning("Can't find end of inset in revert_url!")
1434 k = find_default_layout(document, i, j)
1436 document.warning("Can't find default layout in revert_url!")
1439 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1440 if l == -1 or l >= j:
1441 document.warning("Can't find end of default layout in revert_url!")
1444 # OK, so the inset's data is between lines k and l.
1445 data = " ".join(document.body[k+1:l])
1447 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1449 document.body[i:j+1] = newinset
1450 i = i + len(newinset)
1453 def convert_include(document):
1454 'Converts include insets to new format.'
1456 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1458 i = find_token(document.body, "\\begin_inset Include", i)
1461 line = document.body[i]
1462 previewline = document.body[i + 1]
1465 document.warning("Unable to match line " + str(i) + " of body!")
1471 insertion = ["\\begin_inset CommandInset include",
1472 "LatexCommand " + cmd, previewline,
1473 "filename \"" + fn + "\""]
1476 insertion.append("lstparams " + '"' + opt + '"')
1478 document.body[i : i + 2] = insertion
1482 def revert_include(document):
1483 'Reverts include insets to old format.'
1485 r0 = re.compile('preview.*')
1486 r1 = re.compile('LatexCommand (.+)')
1487 r2 = re.compile('filename "(.+)"')
1488 r3 = re.compile('lstparams "(.*)"')
1490 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1494 m = r1.match(document.body[nextline])
1496 document.warning("Malformed LyX document: No LatexCommand line for `" +
1497 document.body[i] + "' on line " + str(i) + ".")
1502 if r0.match(document.body[nextline]):
1503 previewline = document.body[nextline]
1507 m = r2.match(document.body[nextline])
1509 document.warning("Malformed LyX document: No filename line for `" + \
1510 document.body[i] + "' on line " + str(i) + ".")
1516 if (cmd == "lstinputlisting"):
1517 m = r3.match(document.body[nextline])
1519 options = m.group(1)
1522 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1524 newline += ("[" + options + "]")
1525 insertion = [newline]
1526 if previewline != "":
1527 insertion.append(previewline)
1528 document.body[i : nextline] = insertion
1532 def revert_albanian(document):
1533 "Set language Albanian to English"
1535 if document.language == "albanian":
1536 document.language = "english"
1537 i = find_token(document.header, "\\language", 0)
1539 document.header[i] = "\\language english"
1542 j = find_token(document.body, "\\lang albanian", j)
1545 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1549 def revert_lowersorbian(document):
1550 "Set language lower Sorbian to English"
1552 if document.language == "lowersorbian":
1553 document.language = "english"
1554 i = find_token(document.header, "\\language", 0)
1556 document.header[i] = "\\language english"
1559 j = find_token(document.body, "\\lang lowersorbian", j)
1562 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1566 def revert_uppersorbian(document):
1567 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1569 if document.language == "uppersorbian":
1570 document.language = "usorbian"
1571 i = find_token(document.header, "\\language", 0)
1573 document.header[i] = "\\language usorbian"
1576 j = find_token(document.body, "\\lang uppersorbian", j)
1579 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1583 def convert_usorbian(document):
1584 "Set language usorbian to uppersorbian"
1586 if document.language == "usorbian":
1587 document.language = "uppersorbian"
1588 i = find_token(document.header, "\\language", 0)
1590 document.header[i] = "\\language uppersorbian"
1593 j = find_token(document.body, "\\lang usorbian", j)
1596 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1600 def convert_macro_global(document):
1601 "Remove TeX code command \global when it is in front of a macro"
1602 # math macros are nowadays already defined \global, so that an additional
1603 # \global would make the document uncompilable, see
1604 # http://www.lyx.org/trac/ticket/5371
1605 # We're looking for something like this:
1609 # \begin_layout Plain Layout
1619 # \begin_inset FormulaMacro
1620 # \renewcommand{\foo}{123}
1624 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1627 # if i <= 13, then there isn't enough room for the ERT
1631 if document.body[i-6] == "global":
1632 del document.body[i-13 : i]
1638 def revert_macro_optional_params(document):
1639 "Convert macro definitions with optional parameters into ERTs"
1640 # Stub to convert macro definitions with one or more optional parameters
1641 # into uninterpreted ERT insets
1644 def revert_hyperlinktype(document):
1645 'Reverts hyperlink type'
1649 i = find_token(document.body, "target", i)
1652 j = find_token(document.body, "type", i)
1656 del document.body[j]
1660 def revert_pagebreak(document):
1661 'Reverts pagebreak to ERT'
1664 i = find_token(document.body, "\\pagebreak", i)
1667 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1668 '\\begin_layout Standard\n\n\n\\backslash\n' \
1669 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1673 def revert_linebreak(document):
1674 'Reverts linebreak to ERT'
1677 i = find_token(document.body, "\\linebreak", i)
1680 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1681 '\\begin_layout Standard\n\n\n\\backslash\n' \
1682 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1686 def revert_latin(document):
1687 "Set language Latin to English"
1689 if document.language == "latin":
1690 document.language = "english"
1691 i = find_token(document.header, "\\language", 0)
1693 document.header[i] = "\\language english"
1696 j = find_token(document.body, "\\lang latin", j)
1699 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1703 def revert_samin(document):
1704 "Set language North Sami to English"
1706 if document.language == "samin":
1707 document.language = "english"
1708 i = find_token(document.header, "\\language", 0)
1710 document.header[i] = "\\language english"
1713 j = find_token(document.body, "\\lang samin", j)
1716 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1720 def convert_serbocroatian(document):
1721 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1723 if document.language == "serbocroatian":
1724 document.language = "croatian"
1725 i = find_token(document.header, "\\language", 0)
1727 document.header[i] = "\\language croatian"
1730 j = find_token(document.body, "\\lang serbocroatian", j)
1733 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1737 def convert_framed_notes(document):
1738 "Convert framed notes to boxes. "
1741 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1744 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1753 'height_special "totalheight"']
1754 document.body[i:i+1] = subst
1758 def convert_module_names(document):
1759 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1760 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1761 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1762 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1763 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1764 modlist = document.get_module_list()
1765 if len(modlist) == 0:
1769 if mod in modulemap:
1770 newmodlist.append(modulemap[mod])
1772 document.warning("Can't find module %s in the module map!" % mod)
1773 newmodlist.append(mod)
1774 document.set_module_list(newmodlist)
1777 def revert_module_names(document):
1778 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1779 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1780 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1781 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1782 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1783 modlist = document.get_module_list()
1784 if len(modlist) == 0:
1788 if mod in modulemap:
1789 newmodlist.append(modulemap[mod])
1791 document.warning("Can't find module %s in the module map!" % mod)
1792 newmodlist.append(mod)
1793 document.set_module_list(newmodlist)
1796 def revert_colsep(document):
1797 i = find_token(document.header, "\\columnsep", 0)
1800 colsepline = document.header[i]
1801 r = re.compile(r'\\columnsep (.*)')
1802 m = r.match(colsepline)
1804 document.warning("Malformed column separation line!")
1807 del document.header[i]
1808 #it seems to be safe to add the package even if it is already used
1809 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1811 add_to_preamble(document, pretext)
1814 def revert_framed_notes(document):
1815 "Revert framed boxes to notes. "
1818 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1822 j = find_end_of_inset(document.body, i + 1)
1825 document.warning("Malformed LyX document: Could not find end of Box inset.")
1828 k = find_token(document.body, "status", i + 1, j)
1830 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1833 status = document.body[k]
1834 l = find_default_layout(document, i + 1, j)
1836 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1839 m = find_token(document.body, "\\end_layout", i + 1, j)
1841 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1844 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1845 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1846 if ibox == -1 and pbox == -1:
1847 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1848 del document.body[i+1:k]
1850 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1851 subst1 = [document.body[l],
1852 "\\begin_inset Note Shaded",
1854 '\\begin_layout Standard']
1855 document.body[l:l + 1] = subst1
1856 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1857 document.body[m:m + 1] = subst2
1861 def revert_slash(document):
1862 'Revert \\SpecialChar \\slash{} to ERT'
1864 while i < len(document.body):
1865 m = re.match(r'(.*)\\SpecialChar \\slash{}(.*)', document.body[i])
1870 '\\begin_inset ERT',
1871 'status collapsed', '',
1872 '\\begin_layout Standard',
1873 '', '', '\\backslash',
1878 document.body[i: i+1] = subst
1884 def revert_nobreakdash(document):
1885 'Revert \\SpecialChar \\nobreakdash- to ERT'
1887 while i < len(document.body):
1888 m = re.match(r'(.*)\\SpecialChar \\nobreakdash-(.*)', document.body[i])
1893 '\\begin_inset ERT',
1894 'status collapsed', '',
1895 '\\begin_layout Standard', '', '',
1901 document.body[i: i+1] = subst
1903 j = find_token(document.header, "\\use_amsmath", 0)
1905 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1908 document.header[j] = "\\use_amsmath 2"
1913 #Returns number of lines added/removed
1914 def revert_nocite_key(body, start, end):
1915 'key "..." -> \nocite{...}'
1916 r = re.compile(r'^key "(.*)"')
1920 m = r.match(body[i])
1922 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1923 j += 1 # because we added a line
1924 i += 2 # skip that line
1927 j -= 1 # because we deleted a line
1928 # no need to change i, since it now points to the next line
1932 def revert_nocite(document):
1933 "Revert LatexCommand nocite to ERT"
1936 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1939 if (document.body[i+1] != "LatexCommand nocite"):
1940 # note that we already incremented i
1943 insetEnd = find_end_of_inset(document.body, i)
1945 #this should not happen
1946 document.warning("End of CommandInset citation not found in revert_nocite!")
1949 paramLocation = i + 2 #start of the inset's parameters
1951 document.body[i:i+2] = \
1952 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1953 # that added two lines
1956 #print insetEnd, document.body[i: insetEnd + 1]
1957 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1958 #print insetEnd, document.body[i: insetEnd + 1]
1959 document.body.insert(insetEnd, "\\end_layout")
1960 document.body.insert(insetEnd + 1, "")
1964 def revert_btprintall(document):
1965 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1966 i = find_token(document.header, '\\use_bibtopic', 0)
1968 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1970 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1972 while i < len(document.body):
1973 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1976 j = find_end_of_inset(document.body, i + 1)
1978 #this should not happen
1979 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1980 j = len(document.body)
1981 # this range isn't really right, but it should be OK, since we shouldn't
1982 # see more than one matching line in each inset
1984 for k in range(i, j):
1985 if (document.body[k] == 'btprint "btPrintAll"'):
1986 del document.body[k]
1987 subst = ["\\begin_inset ERT",
1988 "status collapsed", "",
1989 "\\begin_layout Standard", "",
1994 document.body[i:i] = subst
1995 addlines = addedlines + len(subst) - 1
1999 def revert_bahasam(document):
2000 "Set language Bahasa Malaysia to Bahasa Indonesia"
2002 if document.language == "bahasam":
2003 document.language = "bahasa"
2004 i = find_token(document.header, "\\language", 0)
2006 document.header[i] = "\\language bahasa"
2009 j = find_token(document.body, "\\lang bahasam", j)
2012 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
2016 def revert_interlingua(document):
2017 "Set language Interlingua to English"
2019 if document.language == "interlingua":
2020 document.language = "english"
2021 i = find_token(document.header, "\\language", 0)
2023 document.header[i] = "\\language english"
2026 j = find_token(document.body, "\\lang interlingua", j)
2029 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
2033 def revert_serbianlatin(document):
2034 "Set language Serbian-Latin to Croatian"
2036 if document.language == "serbian-latin":
2037 document.language = "croatian"
2038 i = find_token(document.header, "\\language", 0)
2040 document.header[i] = "\\language croatian"
2043 j = find_token(document.body, "\\lang serbian-latin", j)
2046 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
2050 def revert_rotfloat(document):
2051 " Revert sideways custom floats. "
2054 # whitespace intended (exclude \\begin_inset FloatList)
2055 i = find_token(document.body, "\\begin_inset Float ", i)
2058 line = document.body[i]
2059 r = re.compile(r'\\begin_inset Float (.*)$')
2062 document.warning("Unable to match line " + str(i) + " of body!")
2065 floattype = m.group(1)
2066 if floattype == "figure" or floattype == "table":
2069 j = find_end_of_inset(document.body, i)
2071 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
2075 if get_value(document.body, 'sideways', i, j) == "false":
2078 l = find_default_layout(document, i + 1, j)
2080 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2083 subst = ['\\begin_layout Standard',
2084 '\\begin_inset ERT',
2085 'status collapsed', '',
2086 '\\begin_layout Standard', '', '',
2088 'end{sideways' + floattype + '}',
2089 '\\end_layout', '', '\\end_inset']
2090 document.body[j : j+1] = subst
2091 addedLines = len(subst) - 1
2092 del document.body[i+1 : l]
2093 addedLines -= (l-1) - (i+1)
2094 subst = ['\\begin_inset ERT', 'status collapsed', '',
2095 '\\begin_layout Standard', '', '', '\\backslash',
2096 'begin{sideways' + floattype + '}',
2097 '\\end_layout', '', '\\end_inset', '',
2099 document.body[i : i+1] = subst
2100 addedLines += len(subst) - 1
2101 if floattype == "algorithm":
2102 add_to_preamble(document,
2103 ['% Commands inserted by lyx2lyx for sideways algorithm float',
2104 '\\usepackage{rotfloat}',
2105 '\\floatstyle{ruled}',
2106 '\\newfloat{algorithm}{tbp}{loa}',
2107 '\\floatname{algorithm}{Algorithm}'])
2109 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
2113 def revert_widesideways(document):
2114 " Revert wide sideways floats. "
2117 # whitespace intended (exclude \\begin_inset FloatList)
2118 i = find_token(document.body, '\\begin_inset Float ', i)
2121 line = document.body[i]
2122 r = re.compile(r'\\begin_inset Float (.*)$')
2125 document.warning("Unable to match line " + str(i) + " of body!")
2128 floattype = m.group(1)
2129 if floattype != "figure" and floattype != "table":
2132 j = find_end_of_inset(document.body, i)
2134 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2137 if get_value(document.body, 'sideways', i, j) == "false" or \
2138 get_value(document.body, 'wide', i, j) == "false":
2141 l = find_default_layout(document, i + 1, j)
2143 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2146 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2147 'status collapsed', '',
2148 '\\begin_layout Standard', '', '', '\\backslash',
2149 'end{sideways' + floattype + '*}',
2150 '\\end_layout', '', '\\end_inset']
2151 document.body[j : j+1] = subst
2152 addedLines = len(subst) - 1
2153 del document.body[i+1:l-1]
2154 addedLines -= (l-1) - (i+1)
2155 subst = ['\\begin_inset ERT', 'status collapsed', '',
2156 '\\begin_layout Standard', '', '', '\\backslash',
2157 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2158 '\\end_inset', '', '\\end_layout', '']
2159 document.body[i : i+1] = subst
2160 addedLines += len(subst) - 1
2161 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2165 def revert_inset_embedding(document, type):
2166 ' Remove embed tag from certain type of insets'
2169 i = find_token(document.body, "\\begin_inset %s" % type, i)
2172 j = find_end_of_inset(document.body, i)
2174 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2177 k = find_token(document.body, "\tembed", i, j)
2179 k = find_token(document.body, "embed", i, j)
2181 del document.body[k]
2185 def revert_external_embedding(document):
2186 ' Remove embed tag from external inset '
2187 revert_inset_embedding(document, 'External')
2190 def convert_subfig(document):
2191 " Convert subfigures to subfloats. "
2195 i = find_token(document.body, '\\begin_inset Graphics', i)
2198 endInset = find_end_of_inset(document.body, i)
2200 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2203 k = find_token(document.body, '\tsubcaption', i, endInset)
2207 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2211 caption = document.body[l][16:].strip('"')
2212 del document.body[l]
2214 del document.body[k]
2216 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2217 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2218 '', '\\begin_layout Plain Layout'] + latex2lyx(caption, False) + \
2219 [ '\\end_layout', '', '\\end_inset', '',
2220 '\\end_layout', '', '\\begin_layout Plain Layout']
2221 document.body[i : i] = subst
2222 addedLines += len(subst)
2223 endInset += addedLines
2224 subst = ['', '\\end_inset', '', '\\end_layout']
2225 document.body[endInset : endInset] = subst
2226 addedLines += len(subst)
2230 def revert_subfig(document):
2231 " Revert subfloats. "
2234 # whitespace intended (exclude \\begin_inset FloatList)
2235 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2241 j = find_end_of_inset(document.body, i)
2243 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2244 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2246 continue # this will get us back to the outer loop, since j == -1
2247 # look for embedded float (= subfloat)
2248 # whitespace intended (exclude \\begin_inset FloatList)
2249 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2252 # is the subfloat aligned?
2253 al = find_token(document.body, '\\align ', k - 1, j)
2257 if get_value(document.body, '\\align', al) == "center":
2258 alignment_beg = "\\backslash\nbegin{centering}"
2259 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2260 elif get_value(document.body, '\\align', al) == "left":
2261 alignment_beg = "\\backslash\nbegin{raggedright}"
2262 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2263 elif get_value(document.body, '\\align', al) == "right":
2264 alignment_beg = "\\backslash\nbegin{raggedleft}"
2265 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2266 l = find_end_of_inset(document.body, k)
2268 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2271 continue # escape to the outer loop
2272 m = find_default_layout(document, k + 1, l)
2274 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2279 capend = find_end_of_inset(document.body, cap)
2281 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2285 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2287 lblend = find_end_of_inset(document.body, lbl + 1)
2289 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2291 for line in document.body[lbl:lblend + 1]:
2292 if line.startswith('name '):
2293 label = line.split()[1].strip('"')
2300 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2302 optend = find_end_of_inset(document.body, opt)
2304 document.warning("Malformed LyX document: Missing '\\end_inset' (OptArg).")
2306 optc = find_default_layout(document, opt, optend)
2308 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2310 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2311 for line in document.body[optc:optcend]:
2312 if not line.startswith('\\'):
2313 shortcap += line.strip()
2317 for line in document.body[cap:capend]:
2318 if line in document.body[lbl:lblend]:
2320 elif line in document.body[opt:optend]:
2324 caption += lyxline2latex(document, line, inert)
2326 caption += "\n\\backslash\nlabel{" + label + "}"
2327 subst = '\\begin_layout PlainLayout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2328 '\\begin_layout PlainLayout\n\n}' + alignment_end + \
2329 '\n\\end_layout\n\n\\end_inset\n\n' \
2330 '\\end_layout\n\n\\begin_layout PlainLayout\n'
2331 subst = subst.split('\n')
2332 document.body[l : l+1] = subst
2333 addedLines = len(subst) - 1
2334 # this is before l and so is unchanged by the multiline insertion
2336 del document.body[cap:capend+1]
2337 addedLines -= (capend + 1 - cap)
2338 del document.body[k+1:m-1]
2339 addedLines -= (m - 1 - (k + 1))
2340 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2341 '\\begin_layout PlainLayout\n\n' + alignment_beg + '\n\\backslash\n' \
2343 if len(shortcap) > 0:
2344 insertion = insertion + "[" + shortcap + "]"
2345 if len(caption) > 0:
2346 insertion = insertion + "[" + caption + "]"
2347 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2348 insertion = insertion.split('\n')
2349 document.body[k : k + 1] = insertion
2350 addedLines += len(insertion) - 1
2351 al = find_token(document.body, '\\align ', k - 1, j + addedLines)
2353 del document.body[al]
2355 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2359 def revert_wrapplacement(document):
2360 " Revert placement options wrap floats (wrapfig). "
2363 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2366 e = find_end_of_inset(document.body, i)
2367 j = find_token(document.body, "placement", i + 1, e)
2369 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2372 r = re.compile("placement (o|i|l|r|O|I|L|R)")
2373 m = r.match(document.body[j])
2375 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2377 document.body[j] = "placement " + m.group(1).lower()
2381 def remove_extra_embedded_files(document):
2382 " Remove \extra_embedded_files from buffer params "
2383 i = find_token(document.header, '\\extra_embedded_files', 0)
2386 document.header.pop(i)
2389 def convert_spaceinset(document):
2390 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2392 while i < len(document.body):
2393 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2397 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2398 document.body[i: i+1] = subst
2404 def revert_spaceinset(document):
2405 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2408 i = find_token(document.body, "\\begin_inset Space", i)
2411 j = find_end_of_inset(document.body, i)
2413 document.warning("Malformed LyX document: Could not find end of space inset.")
2416 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2417 del document.body[j]
2420 def convert_hfill(document):
2421 " Convert hfill to space inset "
2424 i = find_token(document.body, "\\hfill", i)
2427 subst = document.body[i].replace('\\hfill', \
2428 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2429 subst = subst.split('\n')
2430 document.body[i : i+1] = subst
2434 def revert_hfills(document):
2435 ' Revert \\hfill commands '
2436 hfill = re.compile(r'\\hfill')
2437 dotfill = re.compile(r'\\dotfill')
2438 hrulefill = re.compile(r'\\hrulefill')
2441 i = find_token(document.body, "\\InsetSpace", i)
2444 if hfill.search(document.body[i]):
2445 document.body[i] = \
2446 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2449 if dotfill.search(document.body[i]):
2450 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2451 '\\begin_inset ERT\nstatus collapsed\n\n' \
2452 '\\begin_layout Standard\n\n\n\\backslash\n' \
2453 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2454 subst = subst.split('\n')
2455 document.body[i : i+1] = subst
2458 if hrulefill.search(document.body[i]):
2459 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2460 '\\begin_inset ERT\nstatus collapsed\n\n' \
2461 '\\begin_layout Standard\n\n\n\\backslash\n' \
2462 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2463 subst = subst.split('\n')
2464 document.body[i : i+1] = subst
2469 def revert_hspace(document):
2470 ' Revert \\InsetSpace \\hspace{} to ERT '
2472 hspace = re.compile(r'\\hspace{}')
2473 hstar = re.compile(r'\\hspace\*{}')
2475 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2478 length = get_value(document.body, '\\length', i+1)
2480 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2482 del document.body[i+1]
2484 if hstar.search(document.body[i]):
2485 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2486 '\\begin_inset ERT\nstatus collapsed\n\n' \
2487 '\\begin_layout Standard\n\n\n\\backslash\n' \
2488 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2489 subst = subst.split('\n')
2490 document.body[i : i+1] = subst
2491 addedLines += len(subst) - 1
2494 if hspace.search(document.body[i]):
2495 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2496 '\\begin_inset ERT\nstatus collapsed\n\n' \
2497 '\\begin_layout Standard\n\n\n\\backslash\n' \
2498 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2499 subst = subst.split('\n')
2500 document.body[i : i+1] = subst
2501 addedLines += len(subst) - 1
2507 def revert_protected_hfill(document):
2508 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2511 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2514 j = find_end_of_inset(document.body, i)
2516 document.warning("Malformed LyX document: Could not find end of space inset.")
2519 del document.body[j]
2520 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2521 '\\begin_inset ERT\nstatus collapsed\n\n' \
2522 '\\begin_layout Standard\n\n\n\\backslash\n' \
2523 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2524 subst = subst.split('\n')
2525 document.body[i : i+1] = subst
2529 def revert_leftarrowfill(document):
2530 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2533 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2536 j = find_end_of_inset(document.body, i)
2538 document.warning("Malformed LyX document: Could not find end of space inset.")
2541 del document.body[j]
2542 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2543 '\\begin_inset ERT\nstatus collapsed\n\n' \
2544 '\\begin_layout Standard\n\n\n\\backslash\n' \
2545 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2546 subst = subst.split('\n')
2547 document.body[i : i+1] = subst
2551 def revert_rightarrowfill(document):
2552 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2555 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2558 j = find_end_of_inset(document.body, i)
2560 document.warning("Malformed LyX document: Could not find end of space inset.")
2563 del document.body[j]
2564 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2565 '\\begin_inset ERT\nstatus collapsed\n\n' \
2566 '\\begin_layout Standard\n\n\n\\backslash\n' \
2567 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2568 subst = subst.split('\n')
2569 document.body[i : i+1] = subst
2573 def revert_upbracefill(document):
2574 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2577 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2580 j = find_end_of_inset(document.body, i)
2582 document.warning("Malformed LyX document: Could not find end of space inset.")
2585 del document.body[j]
2586 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2587 '\\begin_inset ERT\nstatus collapsed\n\n' \
2588 '\\begin_layout Standard\n\n\n\\backslash\n' \
2589 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2590 subst = subst.split('\n')
2591 document.body[i : i+1] = subst
2595 def revert_downbracefill(document):
2596 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2599 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2602 j = find_end_of_inset(document.body, i)
2604 document.warning("Malformed LyX document: Could not find end of space inset.")
2607 del document.body[j]
2608 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2609 '\\begin_inset ERT\nstatus collapsed\n\n' \
2610 '\\begin_layout Standard\n\n\n\\backslash\n' \
2611 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2612 subst = subst.split('\n')
2613 document.body[i : i+1] = subst
2617 def revert_local_layout(document):
2618 ' Revert local layout headers.'
2621 i = find_token(document.header, "\\begin_local_layout", i)
2624 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2626 # this should not happen
2628 document.header[i : j + 1] = []
2631 def convert_pagebreaks(document):
2632 ' Convert inline Newpage insets to new format '
2635 i = find_token(document.body, '\\newpage', i)
2638 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2642 i = find_token(document.body, '\\pagebreak', i)
2645 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2649 i = find_token(document.body, '\\clearpage', i)
2652 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2656 i = find_token(document.body, '\\cleardoublepage', i)
2659 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2663 def revert_pagebreaks(document):
2664 ' Revert \\begin_inset Newpage to previous inline format '
2667 i = find_token(document.body, '\\begin_inset Newpage', i)
2670 j = find_end_of_inset(document.body, i)
2672 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2675 del document.body[j]
2676 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2677 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2678 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2679 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2682 def convert_linebreaks(document):
2683 ' Convert inline Newline insets to new format '
2686 i = find_token(document.body, '\\newline', i)
2689 document.body[i:i+1] = ['\\begin_inset Newline newline',
2693 i = find_token(document.body, '\\linebreak', i)
2696 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2700 def revert_linebreaks(document):
2701 ' Revert \\begin_inset Newline to previous inline format '
2704 i = find_token(document.body, '\\begin_inset Newline', i)
2707 j = find_end_of_inset(document.body, i)
2709 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2712 del document.body[j]
2713 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2714 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2717 def convert_japanese_plain(document):
2718 ' Set language japanese-plain to japanese '
2720 if document.language == "japanese-plain":
2721 document.language = "japanese"
2722 i = find_token(document.header, "\\language", 0)
2724 document.header[i] = "\\language japanese"
2727 j = find_token(document.body, "\\lang japanese-plain", j)
2730 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2734 def revert_pdfpages(document):
2735 ' Revert pdfpages external inset to ERT '
2738 i = find_token(document.body, "\\begin_inset External", i)
2741 j = find_end_of_inset(document.body, i)
2743 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2746 if get_value(document.body, 'template', i, j) == "PDFPages":
2747 filename = get_value(document.body, 'filename', i, j)
2749 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2750 for k in range(i, j):
2751 m = r.match(document.body[k])
2754 angle = get_value(document.body, 'rotateAngle', i, j)
2755 width = get_value(document.body, 'width', i, j)
2756 height = get_value(document.body, 'height', i, j)
2757 scale = get_value(document.body, 'scale', i, j)
2758 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2762 options += ",angle=" + angle
2764 options += "angle=" + angle
2767 options += ",width=" + convert_len(width)
2769 options += "width=" + convert_len(width)
2772 options += ",height=" + convert_len(height)
2774 options += "height=" + convert_len(height)
2777 options += ",scale=" + scale
2779 options += "scale=" + scale
2780 if keepAspectRatio != '':
2782 options += ",keepaspectratio"
2784 options += "keepaspectratio"
2786 options = '[' + options + ']'
2787 del document.body[i+1:j+1]
2788 document.body[i:i+1] = ['\\begin_inset ERT',
2791 '\\begin_layout Standard',
2794 'includepdf' + options + '{' + filename + '}',
2798 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2804 def revert_mexican(document):
2805 ' Set language Spanish(Mexico) to Spanish '
2807 if document.language == "spanish-mexico":
2808 document.language = "spanish"
2809 i = find_token(document.header, "\\language", 0)
2811 document.header[i] = "\\language spanish"
2814 j = find_token(document.body, "\\lang spanish-mexico", j)
2817 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2821 def remove_embedding(document):
2822 ' Remove embed tag from all insets '
2823 revert_inset_embedding(document, 'Graphics')
2824 revert_inset_embedding(document, 'External')
2825 revert_inset_embedding(document, 'CommandInset include')
2826 revert_inset_embedding(document, 'CommandInset bibtex')
2829 def revert_master(document):
2830 ' Remove master param '
2831 i = find_token(document.header, "\\master", 0)
2833 del document.header[i]
2836 def revert_graphics_group(document):
2837 ' Revert group information from graphics insets '
2840 i = find_token(document.body, "\\begin_inset Graphics", i)
2843 j = find_end_of_inset(document.body, i)
2845 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2848 k = find_token(document.body, " groupId", i, j)
2852 del document.body[k]
2856 def update_apa_styles(document):
2857 ' Replace obsolete styles '
2859 if document.textclass != "apa":
2862 obsoletedby = { "Acknowledgments": "Acknowledgements",
2863 "Section*": "Section",
2864 "Subsection*": "Subsection",
2865 "Subsubsection*": "Subsubsection",
2866 "Paragraph*": "Paragraph",
2867 "Subparagraph*": "Subparagraph"}
2870 i = find_token(document.body, "\\begin_layout", i)
2874 layout = document.body[i][14:]
2875 if layout in obsoletedby:
2876 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2881 def convert_paper_sizes(document):
2882 ' exchange size options legalpaper and executivepaper to correct order '
2883 # routine is needed to fix http://www.lyx.org/trac/ticket/4868
2886 i = find_token(document.header, "\\papersize executivepaper", 0)
2888 document.header[i] = "\\papersize legalpaper"
2890 j = find_token(document.header, "\\papersize legalpaper", 0)
2892 document.header[j] = "\\papersize executivepaper"
2895 def revert_paper_sizes(document):
2896 ' exchange size options legalpaper and executivepaper to correct order '
2899 i = find_token(document.header, "\\papersize executivepaper", 0)
2901 document.header[i] = "\\papersize legalpaper"
2903 j = find_token(document.header, "\\papersize legalpaper", 0)
2905 document.header[j] = "\\papersize executivepaper"
2908 def convert_InsetSpace(document):
2909 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2912 i = find_token(document.body, "\\begin_inset Space", i)
2915 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2918 def revert_InsetSpace(document):
2919 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2922 i = find_token(document.body, "\\begin_inset space", i)
2925 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2928 def convert_display_enum(document):
2929 " Convert 'display foo' to 'display false/true'"
2932 i = find_token(document.body, "\tdisplay", i)
2935 val = get_value(document.body, 'display', i)
2937 document.body[i] = document.body[i].replace('none', 'false')
2938 if val == "default":
2939 document.body[i] = document.body[i].replace('default', 'true')
2940 if val == "monochrome":
2941 document.body[i] = document.body[i].replace('monochrome', 'true')
2942 if val == "grayscale":
2943 document.body[i] = document.body[i].replace('grayscale', 'true')
2945 document.body[i] = document.body[i].replace('color', 'true')
2946 if val == "preview":
2947 document.body[i] = document.body[i].replace('preview', 'true')
2951 def revert_display_enum(document):
2952 " Revert 'display false/true' to 'display none/color'"
2955 i = find_token(document.body, "\tdisplay", i)
2958 val = get_value(document.body, 'display', i)
2960 document.body[i] = document.body[i].replace('false', 'none')
2962 document.body[i] = document.body[i].replace('true', 'default')
2966 def remove_fontsCJK(document):
2967 ' Remove font_cjk param '
2968 i = find_token(document.header, "\\font_cjk", 0)
2970 del document.header[i]
2973 def convert_plain_layout(document):
2974 " Convert 'PlainLayout' to 'Plain Layout'"
2977 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2980 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2981 '\\begin_layout Plain Layout')
2985 def revert_plain_layout(document):
2986 " Revert 'Plain Layout' to 'PlainLayout'"
2989 i = find_token(document.body, '\\begin_layout Plain Layout', i)
2992 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2993 '\\begin_layout PlainLayout')
2997 def revert_plainlayout(document):
2998 " Revert 'PlainLayout' to 'Standard'"
3001 i = find_token(document.body, '\\begin_layout PlainLayout', i)
3004 # This will be incorrect for some document classes, since Standard is not always
3005 # the default. But (a) it is probably the best we can do and (b) it will actually
3006 # work, in fact, since an unknown layout will be converted to default.
3007 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
3008 '\\begin_layout Standard')
3012 def revert_polytonicgreek(document):
3013 "Set language polytonic Greek to Greek"
3015 if document.language == "polutonikogreek":
3016 document.language = "greek"
3017 i = find_token(document.header, "\\language", 0)
3019 document.header[i] = "\\language greek"
3022 j = find_token(document.body, "\\lang polutonikogreek", j)
3025 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
3029 def revert_removed_modules(document):
3032 i = find_token(document.header, "\\begin_remove_modules", i)
3035 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
3037 # this should not happen
3039 document.header[i : j + 1] = []
3042 def add_plain_layout(document):
3045 i = find_token(document.body, "\\begin_layout", i)
3048 if len(document.body[i].split()) == 1:
3049 document.body[i] = "\\begin_layout Plain Layout"
3053 def revert_tabulators(document):
3054 "Revert tabulators to 4 spaces"
3057 i = find_token(document.body, "\t", i)
3060 document.body[i] = document.body[i].replace("\t", " ")
3064 def revert_tabsize(document):
3065 "Revert the tabsize parameter of listings"
3069 # either it is the only parameter
3070 i = find_token(document.body, 'lstparams "tabsize=4"', i)
3072 del document.body[i]
3074 j = find_token(document.body, "lstparams", j)
3077 pos = document.body[j].find(",tabsize=")
3078 document.body[j] = document.body[j][:pos] + '"'
3083 def revert_mongolian(document):
3084 "Set language Mongolian to English"
3086 if document.language == "mongolian":
3087 document.language = "english"
3088 i = find_token(document.header, "\\language", 0)
3090 document.header[i] = "\\language english"
3093 j = find_token(document.body, "\\lang mongolian", j)
3096 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
3100 def revert_default_options(document):
3101 ' Remove param use_default_options '
3102 i = find_token(document.header, "\\use_default_options", 0)
3104 del document.header[i]
3107 def convert_default_options(document):
3108 ' Add param use_default_options and set it to false '
3109 i = find_token(document.header, "\\textclass", 0)
3111 document.warning("Malformed LyX document: Missing `\\textclass'.")
3113 document.header.insert(i, '\\use_default_options false')
3116 def revert_backref_options(document):
3117 ' Revert option pdf_backref=page to pagebackref '
3118 i = find_token(document.header, "\\pdf_backref page", 0)
3120 document.header[i] = "\\pdf_pagebackref true"
3123 def convert_backref_options(document):
3124 ' We have changed the option pagebackref to backref=true '
3125 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3127 document.header[i] = "\\pdf_backref page"
3128 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3130 del document.header[j]
3131 # backref=true was not a valid option, we meant backref=section
3132 k = find_token(document.header, "\\pdf_backref true", 0)
3133 if k != -1 and i != -1:
3134 del document.header[k]
3135 elif k != -1 and j != -1:
3136 document.header[k] = "\\pdf_backref section"
3139 def convert_charstyle_element(document):
3140 "Convert CharStyle to Element for docbook backend"
3141 if document.backend != "docbook":
3145 i = find_token(document.body, "\\begin_inset Flex CharStyle:", i)
3148 document.body[i] = document.body[i].replace('\\begin_inset Flex CharStyle:',
3149 '\\begin_inset Flex Element:')
3151 def revert_charstyle_element(document):
3152 "Convert Element to CharStyle for docbook backend"
3153 if document.backend != "docbook":
3157 i = find_token(document.body, "\\begin_inset Flex Element:", i)
3160 document.body[i] = document.body[i].replace('\\begin_inset Flex Element:',
3161 '\\begin_inset Flex CharStyle:')
3167 supported_versions = ["1.6.0","1.6"]
3168 convert = [[277, [fix_wrong_tables]],
3169 [278, [close_begin_deeper]],
3170 [279, [long_charstyle_names]],
3171 [280, [axe_show_label]],
3174 [283, [convert_flex]],
3178 [287, [convert_wrapfig_options]],
3179 [288, [convert_inset_command]],
3180 [289, [convert_latexcommand_index]],
3183 [292, [convert_japanese_cjk]],
3185 [294, [convert_pdf_options]],
3186 [295, [convert_htmlurl, convert_url]],
3187 [296, [convert_include]],
3188 [297, [convert_usorbian]],
3189 [298, [convert_macro_global]],
3194 [303, [convert_serbocroatian]],
3195 [304, [convert_framed_notes]],
3202 [311, [convert_ams_classes]],
3204 [313, [convert_module_names]],
3207 [316, [convert_subfig]],
3210 [319, [convert_spaceinset, convert_hfill]],
3212 [321, [convert_tablines]],
3213 [322, [convert_plain_layout]],
3214 [323, [convert_pagebreaks]],
3215 [324, [convert_linebreaks]],
3216 [325, [convert_japanese_plain]],
3219 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3222 [331, [convert_ltcaption]],
3224 [333, [update_apa_styles]],
3225 [334, [convert_paper_sizes]],
3226 [335, [convert_InsetSpace]],
3228 [337, [convert_display_enum]],
3231 [340, [add_plain_layout]],
3234 [343, [convert_default_options]],
3235 [344, [convert_backref_options]],
3236 [345, [convert_charstyle_element]]
3239 revert = [[344, [revert_charstyle_element]],
3240 [343, [revert_backref_options]],
3241 [342, [revert_default_options]],
3242 [341, [revert_mongolian]],
3243 [340, [revert_tabulators, revert_tabsize]],
3245 [338, [revert_removed_modules]],
3246 [337, [revert_polytonicgreek]],
3247 [336, [revert_display_enum]],
3248 [335, [remove_fontsCJK]],
3249 [334, [revert_InsetSpace]],
3250 [333, [revert_paper_sizes]],
3252 [331, [revert_graphics_group]],
3253 [330, [revert_ltcaption]],
3254 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
3255 [328, [revert_master]],
3257 [326, [revert_mexican]],
3258 [325, [revert_pdfpages]],
3260 [323, [revert_linebreaks]],
3261 [322, [revert_pagebreaks]],
3262 [321, [revert_local_layout, revert_plain_layout]],
3263 [320, [revert_tablines]],
3264 [319, [revert_protected_hfill]],
3265 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3266 [317, [remove_extra_embedded_files]],
3267 [316, [revert_wrapplacement]],
3268 [315, [revert_subfig]],
3269 [314, [revert_colsep, revert_plainlayout]],
3271 [312, [revert_module_names]],
3272 [311, [revert_rotfloat, revert_widesideways]],
3273 [310, [revert_external_embedding]],
3274 [309, [revert_btprintall]],
3275 [308, [revert_nocite]],
3276 [307, [revert_serbianlatin]],
3277 [306, [revert_slash, revert_nobreakdash]],
3278 [305, [revert_interlingua]],
3279 [304, [revert_bahasam]],
3280 [303, [revert_framed_notes]],
3282 [301, [revert_latin, revert_samin]],
3283 [300, [revert_linebreak]],
3284 [299, [revert_pagebreak]],
3285 [298, [revert_hyperlinktype]],
3286 [297, [revert_macro_optional_params]],
3287 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3288 [295, [revert_include]],
3289 [294, [revert_href, revert_url]],
3290 [293, [revert_pdf_options_2]],
3291 [292, [revert_inset_info]],
3292 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3293 [290, [revert_vietnamese]],
3294 [289, [revert_wraptable]],
3295 [288, [revert_latexcommand_index]],
3296 [287, [revert_inset_command]],
3297 [286, [revert_wrapfig_options]],
3298 [285, [revert_pdf_options]],
3299 [284, [remove_inzip_options]],
3301 [282, [revert_flex]],
3303 [280, [revert_begin_modules]],
3304 [279, [revert_show_label]],
3305 [278, [revert_long_charstyle_names]],
3311 if __name__ == "__main__":