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
26 from unicode_symbols import read_unicodesymbols
28 ####################################################################
29 # Private helper functions
32 def get_value_string(lines, token, start, end = 0, trim = False, default = ""):
33 """ get_value_string(lines, token, start[[, end], trim, default]) -> string
35 Return tokens after token as string, in lines, where
36 token is the first element. When trim is used, the first and last character
37 of the string is trimmed."""
39 val = get_value(lines, token, start, end, "")
47 def find_end_of_inset(lines, i):
48 " Find end of inset, where lines[i] is included."
49 return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
53 # document.body[i] = wrap_insert_ert(...)
54 # wrap_into_ert may returns a multiline string, which should NOT appear
55 # in document.body. Instead, do something like this:
56 # subst = wrap_inset_ert(...)
57 # subst = subst.split('\n')
58 # document.body[i:i+1] = subst
60 # where the last statement resets the counter to accord with the added
62 def wrap_into_ert(string, src, dst):
63 '''Within string, replace occurrences of src with dst, wrapped into ERT
64 E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is:
65 sch<ERT>\\backslash</ERT>"on'''
66 return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
67 + dst + '\n\\end_layout\n\\end_inset\n')
69 def put_cmd_in_ert(string):
70 for rep in unicode_reps:
71 string = string.replace(rep[1], rep[0].replace('\\\\', '\\'))
72 string = string.replace('\\', "\\backslash\n")
73 string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n" \
74 + string + "\n\\end_layout\n\\end_inset"
77 def add_to_preamble(document, text):
78 """ Add text to the preamble if it is not already there.
79 Only the first line is checked!"""
81 if find_token(document.preamble, text[0], 0) != -1:
84 document.preamble.extend(text)
86 def insert_to_preamble(index, document, text):
87 """ Insert text to the preamble at a given line"""
89 document.preamble.insert(index, text)
91 # Convert a LyX length into a LaTeX length
93 units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
94 "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
95 "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
97 # Convert LyX units to LaTeX units
98 for unit in list(units.keys()):
99 if len.find(unit) != -1:
100 len = '%f' % (len2value(len) / 100)
101 len = len.strip('0') + units[unit]
106 # Return the value of len without the unit in numerical form.
108 result = re.search('([+-]?[0-9.]+)', len)
110 return float(result.group(1))
111 # No number means 1.0
114 # Unfortunately, this doesn't really work, since Standard isn't always default.
115 # But it's as good as we can do right now.
116 def find_default_layout(document, start, end):
117 l = find_token(document.body, "\\begin_layout Standard", start, end)
119 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
121 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
124 def get_option(document, m, option, default):
125 l = document.body[m].find(option)
128 val = document.body[m][l:].split('"')[1]
131 def remove_option(document, m, option):
132 l = document.body[m].find(option)
134 val = document.body[m][l:].split('"')[1]
135 document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
138 def set_option(document, m, option, value):
139 l = document.body[m].find(option)
141 oldval = document.body[m][l:].split('"')[1]
142 l = l + len(option + '="')
143 document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
145 document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
149 # FIXME: Remove this function if the version imported from unicode_symbols works.
150 # This function was the predecessor from that function, that in the meanwhile got
152 def read_unicodesymbols2():
153 " Read the unicodesymbols list of unicode characters and corresponding commands."
155 # Provide support for both python 2 and 3
156 PY2 = sys.version_info[0] == 2
159 # End of code to support for both python 2 and 3
161 pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
162 fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
164 # Two backslashes, followed by some non-word character, and then a character
165 # in brackets. The idea is to check for constructs like: \"{u}, which is how
166 # they are written in the unicodesymbols file; but they can also be written
167 # as: \"u or even \" u.
168 r = re.compile(r'\\\\(\W)\{(\w)\}')
169 for line in fp.readlines():
170 if line[0] != '#' and line.strip() != "":
171 line=line.replace(' "',' ') # remove all quotation marks with spaces before
172 line=line.replace('" ',' ') # remove all quotation marks with spaces after
173 line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
175 [ucs4,command,dead] = line.split(None,2)
176 if command[0:1] != "\\":
178 spec_chars.append([command, unichr(eval(ucs4))])
184 # If the character is a double-quote, then we need to escape it, too,
185 # since it is done that way in the LyX file.
186 if m.group(1) == "\"":
189 command += m.group(1) + m.group(2)
190 commandbl += m.group(1) + ' ' + m.group(2)
191 spec_chars.append([command, unichr(eval(ucs4))])
192 spec_chars.append([commandbl, unichr(eval(ucs4))])
197 def extract_argument(line):
198 'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
203 bracere = re.compile("(\s*)(.*)")
204 n = bracere.match(line)
205 whitespace = n.group(1)
208 if brace != "[" and brace != "{":
232 # We never found the matching brace
233 # So, to be on the safe side, let's just return everything
234 # which will then get wrapped as ERT
236 return (line[:pos + 1], line[pos + 1:])
239 def latex2ert(line, isindex):
240 '''Converts LaTeX commands into ERT. line may well be a multi-line
241 string when it is returned.'''
246 ## FIXME Escaped \ ??
247 # This regex looks for a LaTeX command---i.e., something of the form
248 # "\alPhaStuFF", or "\X", where X is any character---where the command
249 # may also be preceded by an additional backslash, which is how it would
250 # appear (e.g.) in an InsetIndex.
251 labelre = re.compile(r'(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)')
253 m = labelre.match(line)
260 (arg, rest) = extract_argument(end)
265 # If we wanted to put labels into an InsetLabel, for example, then we
266 # would just need to test here for cmd == "label" and then take some
267 # appropriate action, i.e., to use arg to get the content and then
268 # wrap it appropriately.
269 cmd = put_cmd_in_ert(cmd)
270 retval += "\n" + cmd + "\n"
272 m = labelre.match(line)
273 # put all remaining braces in ERT
274 line = wrap_into_ert(line, '}', '}')
275 line = wrap_into_ert(line, '{', '{')
277 # active character that is not available in all font encodings
278 line = wrap_into_ert(line, '|', '|')
283 unicode_reps = read_unicodesymbols()
286 #Might should do latex2ert first, then deal with stuff that DOESN'T
287 #end up inside ERT. That routine could be modified so that it returned
288 #a list of lines, and we could then skip ERT bits and only deal with
290 def latex2lyx(data, isindex):
291 '''Takes a string, possibly multi-line, and returns the result of
292 converting LaTeX constructs into LyX constructs. Returns a list of
293 lines, suitable for insertion into document.body.
294 The bool isindex specifies whether we are in an index macro (which
295 has some specific active characters that need to be ERTed).'''
301 # Convert LaTeX to Unicode
302 # Commands of this sort need to be checked to make sure they are
303 # followed by a non-alpha character, lest we replace too much.
304 hardone = re.compile(r'^\\\\[a-zA-Z]+$')
306 for rep in unicode_reps:
307 if hardone.match(rep[0]):
310 pos = data.find(rep[0], pos)
313 nextpos = pos + len(rep[0])
314 if nextpos < len(data) and data[nextpos].isalpha():
315 # not the end of that command
318 data = data[:pos] + rep[1] + data[nextpos:]
321 data = data.replace(rep[0], rep[1])
325 data = wrap_into_ert(data, r'\"', '"')
327 data = data.replace('\\\\', '\\')
330 mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
331 lines = data.split('\n')
333 #document.warning("LINE: " + line)
334 #document.warning(str(i) + ":" + document.body[i])
335 #document.warning("LAST: " + document.body[-1])
340 f = m.group(2).replace('\\\\', '\\')
344 s = latex2ert(s, isindex)
345 subst = s.split('\n')
347 retval.append("\\begin_inset Formula " + f)
348 retval.append("\\end_inset")
350 # Handle whatever is left, which is just text
351 g = latex2ert(g, isindex)
352 subst = g.split('\n')
357 def lyxline2latex(document, line, inert):
358 'Convert some LyX stuff into corresponding LaTeX stuff line-wise, as best we can.'
359 if line.startswith("\\begin_inset Formula"):
361 elif line.startswith("\\begin_inset Quotes"):
362 # For now, we do a very basic reversion. Someone who understands
363 # quotes is welcome to fix it up.
364 qtype = line[20:].strip()
378 elif line.isspace() or \
379 line.startswith("\\begin_layout") or \
380 line.startswith("\\end_layout") or \
381 line.startswith("\\begin_inset") or \
382 line.startswith("\\end_inset") or \
383 line.startswith("\\lang") or \
384 line.strip() == "status collapsed" or \
385 line.strip() == "status open":
389 # this needs to be added to the preamble because of cases like
390 # \textmu, \textbackslash, etc.
391 add_to_preamble(document, ['% added by lyx2lyx for converted entries',
392 '\\@ifundefined{textmu}',
393 ' {\\usepackage{textcomp}}{}'])
394 # a lossless reversion is not possible
395 # try at least to handle some common insets and settings
397 line = line.replace(r'\backslash', '\\')
399 line = line.replace('&', '\\&{}')
400 line = line.replace('#', '\\#{}')
401 line = line.replace('^', '\\^{}')
402 line = line.replace('%', '\\%{}')
403 line = line.replace('_', '\\_{}')
404 line = line.replace('$', '\\${}')
406 # Do the LyX text --> LaTeX conversion
407 for rep in unicode_reps:
408 line = line.replace(rep[1], rep[0].replace('\\\\', '\\') + "{}")
409 line = line.replace(r'\backslash', r'\textbackslash{}')
410 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
411 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
412 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
413 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
414 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
415 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
416 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
417 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
418 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
422 def lyx2latex(document, lines):
423 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
424 # clean up multiline stuff
428 for curline in range(len(lines)):
429 line = lines[curline]
430 if line.startswith("\\begin_inset ERT"):
431 # We don't want to replace things inside ERT, so figure out
432 # where the end of the inset is.
433 ert_end = find_end_of_inset(lines, curline + 1)
435 inert = ert_end >= curline
436 content += lyxline2latex(document, lines[curline], inert)
441 ####################################################################
443 def convert_ltcaption(document):
446 i = find_token(document.body, "\\begin_inset Tabular", i)
449 j = find_end_of_inset(document.body, i + 1)
451 document.warning("Malformed LyX document: Could not find end of tabular.")
455 nrows = int(document.body[i+1].split('"')[3])
456 ncols = int(document.body[i+1].split('"')[5])
459 for k in range(nrows):
460 m = find_token(document.body, "<row", m)
463 for k in range(ncols):
464 m = find_token(document.body, "<cell", m)
466 mend = find_token(document.body, "</cell>", m + 1)
467 # first look for caption insets
468 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
469 # then look for ERT captions
471 mcap = find_token(document.body, "caption", m + 1, mend)
473 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
476 if caption == 'true':
478 set_option(document, r, 'caption', 'true')
479 set_option(document, m, 'multicolumn', '1')
480 set_option(document, m, 'bottomline', 'false')
481 set_option(document, m, 'topline', 'false')
482 set_option(document, m, 'rightline', 'false')
483 set_option(document, m, 'leftline', 'false')
484 #j = find_end_of_inset(document.body, j + 1)
486 set_option(document, m, 'multicolumn', '2')
493 #FIXME Use of wrap_into_ert can confuse lyx2lyx
494 def revert_ltcaption(document):
497 i = find_token(document.body, "\\begin_inset Tabular", i)
500 j = find_end_of_inset(document.body, i + 1)
502 document.warning("Malformed LyX document: Could not find end of tabular.")
507 nrows = int(document.body[i+1].split('"')[3])
508 ncols = int(document.body[i+1].split('"')[5])
510 for k in range(nrows):
511 m = find_token(document.body, "<row", m)
512 caption = get_option(document, m, 'caption', 'false')
513 if caption == 'true':
514 remove_option(document, m, 'caption')
515 for k in range(ncols):
516 m = find_token(document.body, "<cell", m)
517 remove_option(document, m, 'multicolumn')
519 m = find_token(document.body, "\\begin_inset Caption", m)
522 m = find_end_of_inset(document.body, m + 1)
523 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
529 def convert_tablines(document):
532 i = find_token(document.body, "\\begin_inset Tabular", i)
534 # LyX 1.3 inserted an extra space between \begin_inset
535 # and Tabular so let us try if this is the case and fix it.
536 i = find_token(document.body, "\\begin_inset Tabular", i)
540 document.body[i] = "\\begin_inset Tabular"
541 j = find_end_of_inset(document.body, i + 1)
543 document.warning("Malformed LyX document: Could not find end of tabular.")
548 nrows = int(document.body[i+1].split('"')[3])
549 ncols = int(document.body[i+1].split('"')[5])
552 for k in range(ncols):
553 m = find_token(document.body, "<column", m)
554 left = get_option(document, m, 'leftline', 'false')
555 right = get_option(document, m, 'rightline', 'false')
556 col_info.append([left, right])
557 remove_option(document, m, 'leftline')
558 remove_option(document, m, 'rightline')
562 for k in range(nrows):
563 m = find_token(document.body, "<row", m)
564 top = get_option(document, m, 'topline', 'false')
565 bottom = get_option(document, m, 'bottomline', 'false')
566 row_info.append([top, bottom])
567 remove_option(document, m, 'topline')
568 remove_option(document, m, 'bottomline')
573 for k in range(nrows*ncols):
574 m = find_token(document.body, "<cell", m)
575 mc_info.append(get_option(document, m, 'multicolumn', '0'))
578 for l in range(nrows):
579 for k in range(ncols):
580 m = find_token(document.body, '<cell', m)
581 if mc_info[l*ncols + k] == '0':
582 r = set_option(document, m, 'topline', row_info[l][0])
583 r = set_option(document, m, 'bottomline', row_info[l][1])
584 r = set_option(document, m, 'leftline', col_info[k][0])
585 r = set_option(document, m, 'rightline', col_info[k][1])
586 elif mc_info[l*ncols + k] == '1':
588 while s < ncols and mc_info[l*ncols + s] == '2':
590 if s < ncols and mc_info[l*ncols + s] != '1':
591 r = set_option(document, m, 'rightline', col_info[k][1])
592 if k > 0 and mc_info[l*ncols + k - 1] == '0':
593 r = set_option(document, m, 'leftline', col_info[k][0])
598 def revert_tablines(document):
601 i = find_token(document.body, "\\begin_inset Tabular", i)
604 j = find_end_of_inset(document.body, i)
606 document.warning("Malformed LyX document: Could not find end of tabular.")
611 nrows = int(document.body[i+1].split('"')[3])
612 ncols = int(document.body[i+1].split('"')[5])
615 for k in range(nrows*ncols):
616 m = find_token(document.body, "<cell", m)
617 top = get_option(document, m, 'topline', 'false')
618 bottom = get_option(document, m, 'bottomline', 'false')
619 left = get_option(document, m, 'leftline', 'false')
620 right = get_option(document, m, 'rightline', 'false')
621 lines.append([top, bottom, left, right])
624 # we will want to ignore longtable captions
627 for k in range(nrows):
628 m = find_token(document.body, "<row", m)
629 caption = get_option(document, m, 'caption', 'false')
630 caption_info.append([caption])
635 for k in range(ncols):
636 m = find_token(document.body, "<column", m)
638 for l in range(nrows):
639 left = lines[l*ncols + k][2]
640 if left == 'false' and caption_info[l] == 'false':
642 set_option(document, m, 'leftline', left)
644 for l in range(nrows):
645 right = lines[l*ncols + k][3]
646 if right == 'false' and caption_info[l] == 'false':
648 set_option(document, m, 'rightline', right)
652 for k in range(nrows):
653 m = find_token(document.body, "<row", m)
655 for l in range(ncols):
656 top = lines[k*ncols + l][0]
659 if caption_info[k] == 'false':
661 set_option(document, m, 'topline', top)
663 for l in range(ncols):
664 bottom = lines[k*ncols + l][1]
665 if bottom == 'false':
667 if caption_info[k] == 'false':
669 set_option(document, m, 'bottomline', bottom)
675 def fix_wrong_tables(document):
678 i = find_token(document.body, "\\begin_inset Tabular", i)
681 j = find_end_of_inset(document.body, i + 1)
683 document.warning("Malformed LyX document: Could not find end of tabular.")
688 nrows = int(document.body[i+1].split('"')[3])
689 ncols = int(document.body[i+1].split('"')[5])
691 for l in range(nrows):
693 for k in range(ncols):
694 m = find_token(document.body, '<cell', m)
696 if document.body[m].find('multicolumn') != -1:
697 multicol_cont = int(document.body[m].split('"')[1])
699 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
700 document.body[m] = document.body[m][:5] + document.body[m][21:]
703 prev_multicolumn = multicol_cont
710 def close_begin_deeper(document):
714 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
719 if document.body[i][:13] == "\\begin_deeper":
726 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
729 def long_charstyle_names(document):
732 i = find_token(document.body, "\\begin_inset CharStyle", i)
735 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
738 def revert_long_charstyle_names(document):
741 i = find_token(document.body, "\\begin_inset CharStyle", i)
744 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
748 def axe_show_label(document):
751 i = find_token(document.body, "\\begin_inset CharStyle", i)
754 if document.body[i + 1].find("show_label") != -1:
755 if document.body[i + 1].find("true") != -1:
756 document.body[i + 1] = "status open"
757 del document.body[ i + 2]
759 if document.body[i + 1].find("false") != -1:
760 document.body[i + 1] = "status collapsed"
761 del document.body[ i + 2]
763 document.warning("Malformed LyX document: show_label neither false nor true.")
765 document.warning("Malformed LyX document: show_label missing in CharStyle.")
770 def revert_show_label(document):
773 i = find_token(document.body, "\\begin_inset CharStyle", i)
776 if document.body[i + 1].find("status open") != -1:
777 document.body.insert(i + 1, "show_label true")
779 if document.body[i + 1].find("status collapsed") != -1:
780 document.body.insert(i + 1, "show_label false")
782 document.warning("Malformed LyX document: no legal status line in CharStyle.")
785 def revert_begin_modules(document):
788 i = find_token(document.header, "\\begin_modules", i)
791 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
793 # this should not happen
795 document.header[i : j + 1] = []
797 def convert_flex(document):
798 "Convert CharStyle to Flex"
801 i = find_token(document.body, "\\begin_inset CharStyle", i)
804 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
806 def revert_flex(document):
807 "Revert Flex to CharStyle"
810 i = find_token(document.body, "\\begin_inset Flex", i)
813 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
816 def revert_pdf_options(document):
817 "Revert PDF options for hyperref."
818 # store the PDF options and delete the entries from the Lyx file
826 bookmarksnumbered = ""
828 bookmarksopenlevel = ""
836 i = find_token(document.header, "\\use_hyperref", i)
838 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
839 del document.header[i]
840 i = find_token(document.header, "\\pdf_store_options", i)
842 del document.header[i]
843 i = find_token(document.header, "\\pdf_title", 0)
845 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
846 title = ' pdftitle={' + title + '}'
847 del document.header[i]
848 i = find_token(document.header, "\\pdf_author", 0)
850 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
852 author = ' pdfauthor={' + author + '}'
854 author = ',\n pdfauthor={' + author + '}'
855 del document.header[i]
856 i = find_token(document.header, "\\pdf_subject", 0)
858 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
859 if title == "" and author == "":
860 subject = ' pdfsubject={' + subject + '}'
862 subject = ',\n pdfsubject={' + subject + '}'
863 del document.header[i]
864 i = find_token(document.header, "\\pdf_keywords", 0)
866 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
867 if title == "" and author == "" and subject == "":
868 keywords = ' pdfkeywords={' + keywords + '}'
870 keywords = ',\n pdfkeywords={' + keywords + '}'
871 del document.header[i]
872 i = find_token(document.header, "\\pdf_bookmarks", 0)
874 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
875 bookmarks = ',\n bookmarks=' + bookmarks
876 del document.header[i]
877 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
879 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
880 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
881 del document.header[i]
882 i = find_token(document.header, "\\pdf_bookmarksopen", i)
884 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
885 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
886 del document.header[i]
887 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
889 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
890 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
891 del document.header[i]
892 i = find_token(document.header, "\\pdf_breaklinks", i)
894 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
895 breaklinks = ',\n breaklinks=' + breaklinks
896 del document.header[i]
897 i = find_token(document.header, "\\pdf_pdfborder", i)
899 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
900 if pdfborder == 'true':
901 pdfborder = ',\n pdfborder={0 0 0}'
903 pdfborder = ',\n pdfborder={0 0 1}'
904 del document.header[i]
905 i = find_token(document.header, "\\pdf_colorlinks", i)
907 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
908 colorlinks = ',\n colorlinks=' + colorlinks
909 del document.header[i]
910 i = find_token(document.header, "\\pdf_backref", i)
912 backref = get_value_string(document.header, '\\pdf_backref', 0)
913 backref = ',\n backref=' + backref
914 del document.header[i]
915 i = find_token(document.header, "\\pdf_pagebackref", i)
917 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
918 pagebackref = ',\n pagebackref=' + pagebackref
919 del document.header[i]
920 i = find_token(document.header, "\\pdf_pagemode", 0)
922 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
923 pagemode = ',\n pdfpagemode=' + pagemode
924 del document.header[i]
925 i = find_token(document.header, "\\pdf_quoted_options", 0)
927 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
928 if title == "" and author == "" and subject == "" and keywords == "":
929 otheroptions = ' ' + otheroptions
931 otheroptions = ',\n ' + otheroptions
932 del document.header[i]
934 # write to the preamble when hyperref was used
936 # preamble write preparations
937 # bookmark numbers are only output when they are turned on
938 if bookmarksopen == ',\n bookmarksopen=true':
939 bookmarksopen = bookmarksopen + bookmarksopenlevel
940 if bookmarks == ',\n bookmarks=true':
941 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
943 bookmarks = bookmarks
944 # hypersetup is only output when there are things to be set up
945 setupstart = '\\hypersetup{%\n'
947 if otheroptions == "" and title == "" and author == ""\
948 and subject == "" and keywords == "":
952 # babel must be loaded before hyperref and hyperref the first part
953 # of the preamble, like in LyX 1.6
954 insert_to_preamble(0, document,
955 '% Commands inserted by lyx2lyx for PDF properties\n'
956 + '\\usepackage{babel}\n'
957 + '\\usepackage[unicode=true'
976 def remove_inzip_options(document):
977 "Remove inzipName and embed options from the Graphics inset"
980 i = find_token(document.body, "\\begin_inset Graphics", i)
983 j = find_end_of_inset(document.body, i + 1)
986 document.warning("Malformed LyX document: Could not find end of graphics inset.")
989 # If there's a inzip param, just remove that
990 k = find_token(document.body, "\tinzipName", i + 1, j)
993 # embed option must follow the inzipName option
994 del document.body[k+1]
998 def convert_inset_command(document):
1001 \begin_inset LatexCommand cmd
1003 \begin_inset CommandInset InsetType
1008 i = find_token(document.body, "\\begin_inset LatexCommand", i)
1011 line = document.body[i]
1012 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
1014 cmdName = m.group(1)
1016 #this is adapted from factory.cpp
1017 if cmdName[0:4].lower() == "cite":
1018 insetName = "citation"
1019 elif cmdName == "url" or cmdName == "htmlurl":
1021 elif cmdName[-3:] == "ref":
1023 elif cmdName == "tableofcontents":
1025 elif cmdName == "printnomenclature":
1026 insetName = "nomencl_print"
1027 elif cmdName == "printindex":
1028 insetName = "index_print"
1031 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
1032 document.body[i : i+1] = insertion
1035 def revert_inset_command(document):
1038 \begin_inset CommandInset InsetType
1041 \begin_inset LatexCommand cmd
1042 Some insets may end up being converted to insets earlier versions of LyX
1043 will not be able to recognize. Not sure what to do about that.
1047 i = find_token(document.body, "\\begin_inset CommandInset", i)
1050 nextline = document.body[i+1]
1051 r = re.compile(r'LatexCommand\s+(.*)$')
1052 m = r.match(nextline)
1054 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
1057 cmdName = m.group(1)
1058 insertion = ["\\begin_inset LatexCommand " + cmdName]
1059 document.body[i : i+2] = insertion
1062 def convert_wrapfig_options(document):
1063 "Convert optional options for wrap floats (wrapfig)."
1064 # adds the tokens "lines", "placement", and "overhang"
1067 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1070 document.body.insert(i + 1, "lines 0")
1071 j = find_token(document.body, "placement", i)
1072 # placement can be already set or not; if not, set it
1074 document.body.insert(i + 3, "overhang 0col%")
1076 document.body.insert(i + 2, "placement o")
1077 document.body.insert(i + 3, "overhang 0col%")
1081 def revert_wrapfig_options(document):
1082 "Revert optional options for wrap floats (wrapfig)."
1085 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1088 j = find_end_of_inset(document.body, i)
1090 document.warning("Can't find end of Wrap inset at line " + str(i))
1093 k = find_default_layout(document, i, j)
1095 document.warning("Can't find default layout for Wrap figure!")
1098 # Options should be between i and k now
1099 l = find_token(document.body, "lines", i, k)
1101 document.warning("Can't find lines option for Wrap figure!")
1104 m = find_token(document.body, "overhang", i + 1, k)
1106 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1109 # Do these in reverse order
1110 del document.body[m]
1111 del document.body[l]
1115 def convert_latexcommand_index(document):
1116 "Convert from LatexCommand form to collapsible form."
1118 r1 = re.compile('name "(.*)"')
1120 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1123 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1126 j = find_end_of_inset(document.body, i + 1)
1128 document.warning("Unable to find end of index inset at line " + str(i) + "!")
1131 m = r1.match(document.body[i + 2])
1133 document.warning("Unable to match: " + document.body[i+2])
1134 # this can happen with empty index insets!
1137 fullcontent = m.group(1)
1138 linelist = latex2lyx(fullcontent, True)
1139 #document.warning(fullcontent)
1141 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1142 linelist + ["\\end_layout"]
1143 document.body[i : j] = linelist
1144 i += len(linelist) - (j - i)
1147 def revert_latexcommand_index(document):
1148 "Revert from collapsible form to LatexCommand form."
1151 i = find_token(document.body, "\\begin_inset Index", i)
1154 j = find_end_of_inset(document.body, i + 1)
1158 content = lyx2latex(document, document.body[i:j])
1160 content = content.replace('"', r'\"')
1161 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1162 "name " + '"' + content + '"', ""]
1166 def revert_wraptable(document):
1167 "Revert wrap table to wrap figure."
1170 i = find_token(document.body, "\\begin_inset Wrap table", i)
1173 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1177 def revert_vietnamese(document):
1178 "Set language Vietnamese to English"
1179 # Set document language from Vietnamese to English
1181 if document.language == "vietnamese":
1182 document.language = "english"
1183 i = find_token(document.header, "\\language", 0)
1185 document.header[i] = "\\language english"
1188 j = find_token(document.body, "\\lang vietnamese", j)
1191 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1195 def convert_japanese_cjk(document):
1196 "Set language japanese to japanese-cjk"
1197 # Set document language from japanese-plain to japanese
1199 if document.language == "japanese":
1200 document.language = "japanese-cjk"
1201 i = find_token(document.header, "\\language", 0)
1203 document.header[i] = "\\language japanese-cjk"
1206 j = find_token(document.body, "\\lang japanese", j)
1209 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1213 def revert_japanese(document):
1214 "Set language japanese-plain to japanese"
1215 # Set document language from japanese-plain to japanese
1217 if document.language == "japanese-plain":
1218 document.language = "japanese"
1219 i = find_token(document.header, "\\language", 0)
1221 document.header[i] = "\\language japanese"
1224 j = find_token(document.body, "\\lang japanese-plain", j)
1227 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1231 def revert_japanese_cjk(document):
1232 "Set language japanese-cjk to japanese"
1233 # Set document language from japanese-plain to japanese
1235 if document.language == "japanese-cjk":
1236 document.language = "japanese"
1237 i = find_token(document.header, "\\language", 0)
1239 document.header[i] = "\\language japanese"
1242 j = find_token(document.body, "\\lang japanese-cjk", j)
1245 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1249 def revert_japanese_encoding(document):
1250 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1251 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1253 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1255 document.header[i] = "\\inputencoding EUC-JP"
1257 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1259 document.header[j] = "\\inputencoding JIS"
1261 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1262 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1263 document.header[k] = "\\inputencoding UTF8"
1266 def revert_inset_info(document):
1267 'Replace info inset with its content'
1270 i = find_token(document.body, '\\begin_inset Info', i)
1273 j = find_end_of_inset(document.body, i + 1)
1276 document.warning("Malformed LyX document: Could not find end of Info inset.")
1281 for k in range(i, j+1):
1282 if document.body[k].startswith("arg"):
1283 arg = document.body[k][3:].strip()
1284 # remove embracing quotation marks
1287 if arg[len(arg) - 1] == '"':
1288 arg = arg[:len(arg) - 1]
1289 # \" to straight quote
1290 arg = arg.replace(r'\"', '"')
1292 arg = arg.replace(r'\\', "\\backslash\n")
1293 if document.body[k].startswith("type"):
1294 type = document.body[k][4:].strip().strip('"')
1295 # I think there is a newline after \\end_inset, which should be removed.
1296 if document.body[j + 1].strip() == "":
1297 document.body[i : (j + 2)] = [type + ':' + arg]
1299 document.body[i : (j + 1)] = [type + ':' + arg]
1302 def convert_pdf_options(document):
1303 # Set the pdfusetitle tag, delete the pdf_store_options,
1304 # set quotes for bookmarksopenlevel"
1305 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1307 k = find_token(document.header, "\\use_hyperref", 0)
1308 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1309 k = find_token(document.header, "\\pdf_store_options", 0)
1311 del document.header[k]
1312 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1314 document.header[i] = document.header[i].replace('"', '')
1317 def revert_pdf_options_2(document):
1318 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1319 k = find_token(document.header, "\\use_hyperref", 0)
1320 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1322 del document.header[i]
1323 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1325 values = document.header[i].split()
1326 values[1] = ' "' + values[1] + '"'
1327 document.header[i] = ''.join(values)
1330 def convert_htmlurl(document):
1331 'Convert "htmlurl" to "href" insets for docbook'
1332 if document.backend != "docbook":
1336 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1339 document.body[i] = "\\begin_inset CommandInset href"
1340 document.body[i + 1] = "LatexCommand href"
1344 def convert_url(document):
1345 'Convert url insets to url charstyles'
1346 if document.backend == "docbook":
1350 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1353 n = find_token(document.body, "name", i)
1355 # place the URL name in typewriter before the new URL insert
1356 # grab the name 'bla' from the e.g. the line 'name "bla"',
1357 # therefore start with the 6th character
1358 name = document.body[n][6:-1]
1359 newname = [name + " "]
1360 document.body[i:i] = newname
1362 j = find_token(document.body, "target", i)
1364 document.warning("Malformed LyX document: Can't find target for url inset")
1367 target = document.body[j][8:-1]
1368 k = find_token(document.body, "\\end_inset", j)
1370 document.warning("Malformed LyX document: Can't find end of url inset")
1373 newstuff = ["\\begin_inset Flex URL",
1374 "status collapsed", "",
1375 "\\begin_layout Standard",
1380 document.body[i:k] = newstuff
1381 i = i + len(newstuff)
1383 def convert_ams_classes(document):
1384 tc = document.textclass
1385 if (tc != "amsart" and tc != "amsart-plain" and
1386 tc != "amsart-seq" and tc != "amsbook"):
1388 if tc == "amsart-plain":
1389 document.textclass = "amsart"
1390 document.set_textclass()
1391 document.add_module("Theorems (Starred)")
1393 if tc == "amsart-seq":
1394 document.textclass = "amsart"
1395 document.set_textclass()
1396 document.add_module("Theorems (AMS)")
1398 #Now we want to see if any of the environments in the extended theorems
1399 #module were used in this document. If so, we'll add that module, too.
1400 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1401 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1404 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1407 i = find_token(document.body, "\\begin_layout", i)
1410 m = r.match(document.body[i])
1412 # This is an empty layout
1413 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1417 if layouts.count(m) != 0:
1418 document.add_module("Theorems (AMS-Extended)")
1422 def revert_href(document):
1423 'Reverts hyperlink insets (href) to url insets (url)'
1426 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1429 document.body[i : i + 2] = \
1430 ["\\begin_inset CommandInset url", "LatexCommand url"]
1433 def revert_url(document):
1434 'Reverts Flex URL insets to old-style URL insets'
1437 i = find_token(document.body, "\\begin_inset Flex URL", i)
1440 j = find_end_of_inset(document.body, i)
1442 document.warning("Can't find end of inset in revert_url!")
1444 k = find_default_layout(document, i, j)
1446 document.warning("Can't find default layout in revert_url!")
1449 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1450 if l == -1 or l >= j:
1451 document.warning("Can't find end of default layout in revert_url!")
1454 # OK, so the inset's data is between lines k and l.
1455 data = " ".join(document.body[k+1:l])
1457 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1459 document.body[i:j+1] = newinset
1460 i = i + len(newinset)
1463 def convert_include(document):
1464 'Converts include insets to new format.'
1466 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1468 i = find_token(document.body, "\\begin_inset Include", i)
1471 line = document.body[i]
1472 previewline = document.body[i + 1]
1475 document.warning("Unable to match line " + str(i) + " of body!")
1481 insertion = ["\\begin_inset CommandInset include",
1482 "LatexCommand " + cmd, previewline,
1483 "filename \"" + fn + "\""]
1486 insertion.append("lstparams " + '"' + opt + '"')
1488 document.body[i : i + 2] = insertion
1492 def revert_include(document):
1493 'Reverts include insets to old format.'
1495 r0 = re.compile('preview.*')
1496 r1 = re.compile('LatexCommand (.+)')
1497 r2 = re.compile('filename "(.+)"')
1498 r3 = re.compile('lstparams "(.*)"')
1500 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1504 m = r1.match(document.body[nextline])
1506 document.warning("Malformed LyX document: No LatexCommand line for `" +
1507 document.body[i] + "' on line " + str(i) + ".")
1512 if r0.match(document.body[nextline]):
1513 previewline = document.body[nextline]
1517 m = r2.match(document.body[nextline])
1519 document.warning("Malformed LyX document: No filename line for `" + \
1520 document.body[i] + "' on line " + str(i) + ".")
1526 if (cmd == "lstinputlisting"):
1527 m = r3.match(document.body[nextline])
1529 options = m.group(1)
1532 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1534 newline += ("[" + options + "]")
1535 insertion = [newline]
1536 if previewline != "":
1537 insertion.append(previewline)
1538 document.body[i : nextline] = insertion
1542 def revert_albanian(document):
1543 "Set language Albanian to English"
1545 if document.language == "albanian":
1546 document.language = "english"
1547 i = find_token(document.header, "\\language", 0)
1549 document.header[i] = "\\language english"
1552 j = find_token(document.body, "\\lang albanian", j)
1555 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1559 def revert_lowersorbian(document):
1560 "Set language lower Sorbian to English"
1562 if document.language == "lowersorbian":
1563 document.language = "english"
1564 i = find_token(document.header, "\\language", 0)
1566 document.header[i] = "\\language english"
1569 j = find_token(document.body, "\\lang lowersorbian", j)
1572 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1576 def revert_uppersorbian(document):
1577 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1579 if document.language == "uppersorbian":
1580 document.language = "usorbian"
1581 i = find_token(document.header, "\\language", 0)
1583 document.header[i] = "\\language usorbian"
1586 j = find_token(document.body, "\\lang uppersorbian", j)
1589 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1593 def convert_usorbian(document):
1594 "Set language usorbian to uppersorbian"
1596 if document.language == "usorbian":
1597 document.language = "uppersorbian"
1598 i = find_token(document.header, "\\language", 0)
1600 document.header[i] = "\\language uppersorbian"
1603 j = find_token(document.body, "\\lang usorbian", j)
1606 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1610 def convert_macro_global(document):
1611 "Remove TeX code command \global when it is in front of a macro"
1612 # math macros are nowadays already defined \global, so that an additional
1613 # \global would make the document uncompilable, see
1614 # http://www.lyx.org/trac/ticket/5371
1615 # We're looking for something like this:
1619 # \begin_layout Plain Layout
1629 # \begin_inset FormulaMacro
1630 # \renewcommand{\foo}{123}
1634 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1637 # if i <= 13, then there isn't enough room for the ERT
1641 if document.body[i-6] == "global":
1642 del document.body[i-13 : i]
1648 def revert_macro_optional_params(document):
1649 "Convert macro definitions with optional parameters into ERTs"
1650 # Stub to convert macro definitions with one or more optional parameters
1651 # into uninterpreted ERT insets
1654 def revert_hyperlinktype(document):
1655 'Reverts hyperlink type'
1659 i = find_token(document.body, "target", i)
1662 j = find_token(document.body, "type", i)
1666 del document.body[j]
1670 def revert_pagebreak(document):
1671 'Reverts pagebreak to ERT'
1674 i = find_token(document.body, "\\pagebreak", i)
1677 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1678 '\\begin_layout Standard\n\n\n\\backslash\n' \
1679 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1683 def revert_linebreak(document):
1684 'Reverts linebreak to ERT'
1687 i = find_token(document.body, "\\linebreak", i)
1690 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1691 '\\begin_layout Standard\n\n\n\\backslash\n' \
1692 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1696 def revert_latin(document):
1697 "Set language Latin to English"
1699 if document.language == "latin":
1700 document.language = "english"
1701 i = find_token(document.header, "\\language", 0)
1703 document.header[i] = "\\language english"
1706 j = find_token(document.body, "\\lang latin", j)
1709 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1713 def revert_samin(document):
1714 "Set language North Sami to English"
1716 if document.language == "samin":
1717 document.language = "english"
1718 i = find_token(document.header, "\\language", 0)
1720 document.header[i] = "\\language english"
1723 j = find_token(document.body, "\\lang samin", j)
1726 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1730 def convert_serbocroatian(document):
1731 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1733 if document.language == "serbocroatian":
1734 document.language = "croatian"
1735 i = find_token(document.header, "\\language", 0)
1737 document.header[i] = "\\language croatian"
1740 j = find_token(document.body, "\\lang serbocroatian", j)
1743 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1747 def convert_framed_notes(document):
1748 "Convert framed notes to boxes. "
1751 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1754 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1763 'height_special "totalheight"']
1764 document.body[i:i+1] = subst
1768 def convert_module_names(document):
1769 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1770 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1771 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1772 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1773 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1774 modlist = document.get_module_list()
1775 if len(modlist) == 0:
1779 if mod in modulemap:
1780 newmodlist.append(modulemap[mod])
1782 document.warning("Can't find module %s in the module map!" % mod)
1783 newmodlist.append(mod)
1784 document.set_module_list(newmodlist)
1787 def revert_module_names(document):
1788 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1789 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1790 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1791 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1792 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1793 modlist = document.get_module_list()
1794 if len(modlist) == 0:
1798 if mod in modulemap:
1799 newmodlist.append(modulemap[mod])
1801 document.warning("Can't find module %s in the module map!" % mod)
1802 newmodlist.append(mod)
1803 document.set_module_list(newmodlist)
1806 def revert_colsep(document):
1807 i = find_token(document.header, "\\columnsep", 0)
1810 colsepline = document.header[i]
1811 r = re.compile(r'\\columnsep (.*)')
1812 m = r.match(colsepline)
1814 document.warning("Malformed column separation line!")
1817 del document.header[i]
1818 #it seems to be safe to add the package even if it is already used
1819 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1821 add_to_preamble(document, pretext)
1824 def revert_framed_notes(document):
1825 "Revert framed boxes to notes. "
1828 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1832 j = find_end_of_inset(document.body, i + 1)
1835 document.warning("Malformed LyX document: Could not find end of Box inset.")
1838 k = find_token(document.body, "status", i + 1, j)
1840 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1843 status = document.body[k]
1844 l = find_default_layout(document, i + 1, j)
1846 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1849 m = find_token(document.body, "\\end_layout", i + 1, j)
1851 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1854 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1855 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1856 if ibox == -1 and pbox == -1:
1857 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1858 del document.body[i+1:k]
1860 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1861 subst1 = [document.body[l],
1862 "\\begin_inset Note Shaded",
1864 '\\begin_layout Standard']
1865 document.body[l:l + 1] = subst1
1866 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1867 document.body[m:m + 1] = subst2
1871 def revert_slash(document):
1872 'Revert \\SpecialChar \\slash{} to ERT'
1874 while i < len(document.body):
1875 m = re.match(r'(.*)\\SpecialChar \\slash{}(.*)', document.body[i])
1880 '\\begin_inset ERT',
1881 'status collapsed', '',
1882 '\\begin_layout Standard',
1883 '', '', '\\backslash',
1888 document.body[i: i+1] = subst
1894 def revert_nobreakdash(document):
1895 'Revert \\SpecialChar \\nobreakdash- to ERT'
1897 while i < len(document.body):
1898 m = re.match(r'(.*)\\SpecialChar \\nobreakdash-(.*)', document.body[i])
1903 '\\begin_inset ERT',
1904 'status collapsed', '',
1905 '\\begin_layout Standard', '', '',
1911 document.body[i: i+1] = subst
1913 j = find_token(document.header, "\\use_amsmath", 0)
1915 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1918 document.header[j] = "\\use_amsmath 2"
1923 #Returns number of lines added/removed
1924 def revert_nocite_key(body, start, end):
1925 'key "..." -> \nocite{...}'
1926 r = re.compile(r'^key "(.*)"')
1930 m = r.match(body[i])
1932 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1933 j += 1 # because we added a line
1934 i += 2 # skip that line
1937 j -= 1 # because we deleted a line
1938 # no need to change i, since it now points to the next line
1942 def revert_nocite(document):
1943 "Revert LatexCommand nocite to ERT"
1946 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1949 if (document.body[i+1] != "LatexCommand nocite"):
1950 # note that we already incremented i
1953 insetEnd = find_end_of_inset(document.body, i)
1955 #this should not happen
1956 document.warning("End of CommandInset citation not found in revert_nocite!")
1959 paramLocation = i + 2 #start of the inset's parameters
1961 document.body[i:i+2] = \
1962 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1963 # that added two lines
1966 #print insetEnd, document.body[i: insetEnd + 1]
1967 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1968 #print insetEnd, document.body[i: insetEnd + 1]
1969 document.body.insert(insetEnd, "\\end_layout")
1970 document.body.insert(insetEnd + 1, "")
1974 def revert_btprintall(document):
1975 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1976 i = find_token(document.header, '\\use_bibtopic', 0)
1978 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1980 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1982 while i < len(document.body):
1983 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1986 j = find_end_of_inset(document.body, i + 1)
1988 #this should not happen
1989 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1990 j = len(document.body)
1991 # this range isn't really right, but it should be OK, since we shouldn't
1992 # see more than one matching line in each inset
1994 for k in range(i, j):
1995 if (document.body[k] == 'btprint "btPrintAll"'):
1996 del document.body[k]
1997 subst = ["\\begin_inset ERT",
1998 "status collapsed", "",
1999 "\\begin_layout Standard", "",
2004 document.body[i:i] = subst
2005 addlines = addedlines + len(subst) - 1
2009 def revert_bahasam(document):
2010 "Set language Bahasa Malaysia to Bahasa Indonesia"
2012 if document.language == "bahasam":
2013 document.language = "bahasa"
2014 i = find_token(document.header, "\\language", 0)
2016 document.header[i] = "\\language bahasa"
2019 j = find_token(document.body, "\\lang bahasam", j)
2022 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
2026 def revert_interlingua(document):
2027 "Set language Interlingua to English"
2029 if document.language == "interlingua":
2030 document.language = "english"
2031 i = find_token(document.header, "\\language", 0)
2033 document.header[i] = "\\language english"
2036 j = find_token(document.body, "\\lang interlingua", j)
2039 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
2043 def revert_serbianlatin(document):
2044 "Set language Serbian-Latin to Croatian"
2046 if document.language == "serbian-latin":
2047 document.language = "croatian"
2048 i = find_token(document.header, "\\language", 0)
2050 document.header[i] = "\\language croatian"
2053 j = find_token(document.body, "\\lang serbian-latin", j)
2056 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
2060 def revert_rotfloat(document):
2061 " Revert sideways custom floats. "
2064 # whitespace intended (exclude \\begin_inset FloatList)
2065 i = find_token(document.body, "\\begin_inset Float ", i)
2068 line = document.body[i]
2069 r = re.compile(r'\\begin_inset Float (.*)$')
2072 document.warning("Unable to match line " + str(i) + " of body!")
2075 floattype = m.group(1)
2076 if floattype == "figure" or floattype == "table":
2079 j = find_end_of_inset(document.body, i)
2081 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
2085 if get_value(document.body, 'sideways', i, j) == "false":
2088 l = find_default_layout(document, i + 1, j)
2090 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2093 subst = ['\\begin_layout Standard',
2094 '\\begin_inset ERT',
2095 'status collapsed', '',
2096 '\\begin_layout Standard', '', '',
2098 'end{sideways' + floattype + '}',
2099 '\\end_layout', '', '\\end_inset']
2100 document.body[j : j+1] = subst
2101 addedLines = len(subst) - 1
2102 del document.body[i+1 : l]
2103 addedLines -= (l-1) - (i+1)
2104 subst = ['\\begin_inset ERT', 'status collapsed', '',
2105 '\\begin_layout Standard', '', '', '\\backslash',
2106 'begin{sideways' + floattype + '}',
2107 '\\end_layout', '', '\\end_inset', '',
2109 document.body[i : i+1] = subst
2110 addedLines += len(subst) - 1
2111 if floattype == "algorithm":
2112 add_to_preamble(document,
2113 ['% Commands inserted by lyx2lyx for sideways algorithm float',
2114 '\\usepackage{rotfloat}',
2115 '\\floatstyle{ruled}',
2116 '\\newfloat{algorithm}{tbp}{loa}',
2117 '\\floatname{algorithm}{Algorithm}'])
2119 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
2123 def revert_widesideways(document):
2124 " Revert wide sideways floats. "
2127 # whitespace intended (exclude \\begin_inset FloatList)
2128 i = find_token(document.body, '\\begin_inset Float ', i)
2131 line = document.body[i]
2132 r = re.compile(r'\\begin_inset Float (.*)$')
2135 document.warning("Unable to match line " + str(i) + " of body!")
2138 floattype = m.group(1)
2139 if floattype != "figure" and floattype != "table":
2142 j = find_end_of_inset(document.body, i)
2144 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2147 if get_value(document.body, 'sideways', i, j) == "false" or \
2148 get_value(document.body, 'wide', i, j) == "false":
2151 l = find_default_layout(document, i + 1, j)
2153 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2156 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2157 'status collapsed', '',
2158 '\\begin_layout Standard', '', '', '\\backslash',
2159 'end{sideways' + floattype + '*}',
2160 '\\end_layout', '', '\\end_inset']
2161 document.body[j : j+1] = subst
2162 addedLines = len(subst) - 1
2163 del document.body[i+1:l-1]
2164 addedLines -= (l-1) - (i+1)
2165 subst = ['\\begin_inset ERT', 'status collapsed', '',
2166 '\\begin_layout Standard', '', '', '\\backslash',
2167 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2168 '\\end_inset', '', '\\end_layout', '']
2169 document.body[i : i+1] = subst
2170 addedLines += len(subst) - 1
2171 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2175 def revert_inset_embedding(document, type):
2176 ' Remove embed tag from certain type of insets'
2179 i = find_token(document.body, "\\begin_inset %s" % type, i)
2182 j = find_end_of_inset(document.body, i)
2184 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2187 k = find_token(document.body, "\tembed", i, j)
2189 k = find_token(document.body, "embed", i, j)
2191 del document.body[k]
2195 def revert_external_embedding(document):
2196 ' Remove embed tag from external inset '
2197 revert_inset_embedding(document, 'External')
2200 def convert_subfig(document):
2201 " Convert subfigures to subfloats. "
2205 i = find_token(document.body, '\\begin_inset Graphics', i)
2208 endInset = find_end_of_inset(document.body, i)
2210 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2213 k = find_token(document.body, '\tsubcaption', i, endInset)
2217 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2221 caption = document.body[l][16:].strip('"')
2222 del document.body[l]
2224 del document.body[k]
2226 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2227 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2228 '', '\\begin_layout Plain Layout'] + latex2lyx(caption, False) + \
2229 [ '\\end_layout', '', '\\end_inset', '',
2230 '\\end_layout', '', '\\begin_layout Plain Layout']
2231 document.body[i : i] = subst
2232 addedLines += len(subst)
2233 endInset += addedLines
2234 subst = ['', '\\end_inset', '', '\\end_layout']
2235 document.body[endInset : endInset] = subst
2236 addedLines += len(subst)
2240 def revert_subfig(document):
2241 " Revert subfloats. "
2244 # whitespace intended (exclude \\begin_inset FloatList)
2245 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2251 j = find_end_of_inset(document.body, i)
2253 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2254 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2256 continue # this will get us back to the outer loop, since j == -1
2257 # look for embedded float (= subfloat)
2258 # whitespace intended (exclude \\begin_inset FloatList)
2259 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2262 # is the subfloat aligned?
2263 al = find_token(document.body, '\\align ', k - 1, j)
2267 if get_value(document.body, '\\align', al) == "center":
2268 alignment_beg = "\\backslash\nbegin{centering}"
2269 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2270 elif get_value(document.body, '\\align', al) == "left":
2271 alignment_beg = "\\backslash\nbegin{raggedright}"
2272 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2273 elif get_value(document.body, '\\align', al) == "right":
2274 alignment_beg = "\\backslash\nbegin{raggedleft}"
2275 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2276 l = find_end_of_inset(document.body, k)
2278 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2281 continue # escape to the outer loop
2282 m = find_default_layout(document, k + 1, l)
2284 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2289 capend = find_end_of_inset(document.body, cap)
2291 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2295 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2297 lblend = find_end_of_inset(document.body, lbl + 1)
2299 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2301 for line in document.body[lbl:lblend + 1]:
2302 if line.startswith('name '):
2303 label = line.split()[1].strip('"')
2310 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2312 optend = find_end_of_inset(document.body, opt)
2314 document.warning("Malformed LyX document: Missing '\\end_inset' (OptArg).")
2316 optc = find_default_layout(document, opt, optend)
2318 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2320 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2321 for line in document.body[optc:optcend]:
2322 if not line.startswith('\\'):
2323 shortcap += line.strip()
2327 for line in document.body[cap:capend]:
2328 if line in document.body[lbl:lblend]:
2330 elif line in document.body[opt:optend]:
2334 caption += lyxline2latex(document, line, inert)
2336 caption += "\n\\backslash\nlabel{" + label + "}"
2337 subst = '\\begin_layout PlainLayout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2338 '\\begin_layout PlainLayout\n\n}' + alignment_end + \
2339 '\n\\end_layout\n\n\\end_inset\n\n' \
2340 '\\end_layout\n\n\\begin_layout PlainLayout\n'
2341 subst = subst.split('\n')
2342 document.body[l : l+1] = subst
2343 addedLines = len(subst) - 1
2344 # this is before l and so is unchanged by the multiline insertion
2346 del document.body[cap:capend+1]
2347 addedLines -= (capend + 1 - cap)
2348 del document.body[k+1:m-1]
2349 addedLines -= (m - 1 - (k + 1))
2350 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2351 '\\begin_layout PlainLayout\n\n' + alignment_beg + '\n\\backslash\n' \
2353 if len(shortcap) > 0:
2354 insertion = insertion + "[" + shortcap + "]"
2355 if len(caption) > 0:
2356 insertion = insertion + "[" + caption + "]"
2357 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2358 insertion = insertion.split('\n')
2359 document.body[k : k + 1] = insertion
2360 addedLines += len(insertion) - 1
2361 al = find_token(document.body, '\\align ', k - 1, j + addedLines)
2363 del document.body[al]
2365 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2369 def revert_wrapplacement(document):
2370 " Revert placement options wrap floats (wrapfig). "
2373 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2376 e = find_end_of_inset(document.body, i)
2377 j = find_token(document.body, "placement", i + 1, e)
2379 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2382 r = re.compile("placement (o|i|l|r|O|I|L|R)")
2383 m = r.match(document.body[j])
2385 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2387 document.body[j] = "placement " + m.group(1).lower()
2391 def remove_extra_embedded_files(document):
2392 " Remove \extra_embedded_files from buffer params "
2393 i = find_token(document.header, '\\extra_embedded_files', 0)
2396 document.header.pop(i)
2399 def convert_spaceinset(document):
2400 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2402 while i < len(document.body):
2403 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2407 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2408 document.body[i: i+1] = subst
2414 def revert_spaceinset(document):
2415 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2418 i = find_token(document.body, "\\begin_inset Space", i)
2421 j = find_end_of_inset(document.body, i)
2423 document.warning("Malformed LyX document: Could not find end of space inset.")
2426 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2427 del document.body[j]
2430 def convert_hfill(document):
2431 " Convert hfill to space inset "
2434 i = find_token(document.body, "\\hfill", i)
2437 subst = document.body[i].replace('\\hfill', \
2438 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2439 subst = subst.split('\n')
2440 document.body[i : i+1] = subst
2444 def revert_hfills(document):
2445 ' Revert \\hfill commands '
2446 hfill = re.compile(r'\\hfill')
2447 dotfill = re.compile(r'\\dotfill')
2448 hrulefill = re.compile(r'\\hrulefill')
2451 i = find_token(document.body, "\\InsetSpace", i)
2454 if hfill.search(document.body[i]):
2455 document.body[i] = \
2456 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2459 if dotfill.search(document.body[i]):
2460 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2461 '\\begin_inset ERT\nstatus collapsed\n\n' \
2462 '\\begin_layout Standard\n\n\n\\backslash\n' \
2463 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2464 subst = subst.split('\n')
2465 document.body[i : i+1] = subst
2468 if hrulefill.search(document.body[i]):
2469 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2470 '\\begin_inset ERT\nstatus collapsed\n\n' \
2471 '\\begin_layout Standard\n\n\n\\backslash\n' \
2472 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2473 subst = subst.split('\n')
2474 document.body[i : i+1] = subst
2479 def revert_hspace(document):
2480 ' Revert \\InsetSpace \\hspace{} to ERT '
2482 hspace = re.compile(r'\\hspace{}')
2483 hstar = re.compile(r'\\hspace\*{}')
2485 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2488 length = get_value(document.body, '\\length', i+1)
2490 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2492 del document.body[i+1]
2494 if hstar.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
2504 if hspace.search(document.body[i]):
2505 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2506 '\\begin_inset ERT\nstatus collapsed\n\n' \
2507 '\\begin_layout Standard\n\n\n\\backslash\n' \
2508 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2509 subst = subst.split('\n')
2510 document.body[i : i+1] = subst
2511 addedLines += len(subst) - 1
2517 def revert_protected_hfill(document):
2518 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2521 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2524 j = find_end_of_inset(document.body, i)
2526 document.warning("Malformed LyX document: Could not find end of space inset.")
2529 del document.body[j]
2530 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2531 '\\begin_inset ERT\nstatus collapsed\n\n' \
2532 '\\begin_layout Standard\n\n\n\\backslash\n' \
2533 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2534 subst = subst.split('\n')
2535 document.body[i : i+1] = subst
2539 def revert_leftarrowfill(document):
2540 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2543 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2546 j = find_end_of_inset(document.body, i)
2548 document.warning("Malformed LyX document: Could not find end of space inset.")
2551 del document.body[j]
2552 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2553 '\\begin_inset ERT\nstatus collapsed\n\n' \
2554 '\\begin_layout Standard\n\n\n\\backslash\n' \
2555 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2556 subst = subst.split('\n')
2557 document.body[i : i+1] = subst
2561 def revert_rightarrowfill(document):
2562 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2565 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2568 j = find_end_of_inset(document.body, i)
2570 document.warning("Malformed LyX document: Could not find end of space inset.")
2573 del document.body[j]
2574 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2575 '\\begin_inset ERT\nstatus collapsed\n\n' \
2576 '\\begin_layout Standard\n\n\n\\backslash\n' \
2577 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2578 subst = subst.split('\n')
2579 document.body[i : i+1] = subst
2583 def revert_upbracefill(document):
2584 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2587 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2590 j = find_end_of_inset(document.body, i)
2592 document.warning("Malformed LyX document: Could not find end of space inset.")
2595 del document.body[j]
2596 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2597 '\\begin_inset ERT\nstatus collapsed\n\n' \
2598 '\\begin_layout Standard\n\n\n\\backslash\n' \
2599 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2600 subst = subst.split('\n')
2601 document.body[i : i+1] = subst
2605 def revert_downbracefill(document):
2606 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2609 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2612 j = find_end_of_inset(document.body, i)
2614 document.warning("Malformed LyX document: Could not find end of space inset.")
2617 del document.body[j]
2618 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2619 '\\begin_inset ERT\nstatus collapsed\n\n' \
2620 '\\begin_layout Standard\n\n\n\\backslash\n' \
2621 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2622 subst = subst.split('\n')
2623 document.body[i : i+1] = subst
2627 def revert_local_layout(document):
2628 ' Revert local layout headers.'
2631 i = find_token(document.header, "\\begin_local_layout", i)
2634 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2636 # this should not happen
2638 document.header[i : j + 1] = []
2641 def convert_pagebreaks(document):
2642 ' Convert inline Newpage insets to new format '
2645 i = find_token(document.body, '\\newpage', i)
2648 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2652 i = find_token(document.body, '\\pagebreak', i)
2655 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2659 i = find_token(document.body, '\\clearpage', i)
2662 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2666 i = find_token(document.body, '\\cleardoublepage', i)
2669 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2673 def revert_pagebreaks(document):
2674 ' Revert \\begin_inset Newpage to previous inline format '
2677 i = find_token(document.body, '\\begin_inset Newpage', i)
2680 j = find_end_of_inset(document.body, i)
2682 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2685 del document.body[j]
2686 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2687 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2688 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2689 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2692 def convert_linebreaks(document):
2693 ' Convert inline Newline insets to new format '
2696 i = find_token(document.body, '\\newline', i)
2699 document.body[i:i+1] = ['\\begin_inset Newline newline',
2703 i = find_token(document.body, '\\linebreak', i)
2706 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2710 def revert_linebreaks(document):
2711 ' Revert \\begin_inset Newline to previous inline format '
2714 i = find_token(document.body, '\\begin_inset Newline', i)
2717 j = find_end_of_inset(document.body, i)
2719 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2722 del document.body[j]
2723 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2724 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2727 def convert_japanese_plain(document):
2728 ' Set language japanese-plain to japanese '
2730 if document.language == "japanese-plain":
2731 document.language = "japanese"
2732 i = find_token(document.header, "\\language", 0)
2734 document.header[i] = "\\language japanese"
2737 j = find_token(document.body, "\\lang japanese-plain", j)
2740 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2744 def revert_pdfpages(document):
2745 ' Revert pdfpages external inset to ERT '
2748 i = find_token(document.body, "\\begin_inset External", i)
2751 j = find_end_of_inset(document.body, i)
2753 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2756 if get_value(document.body, 'template', i, j) == "PDFPages":
2757 filename = get_value(document.body, 'filename', i, j)
2759 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2760 for k in range(i, j):
2761 m = r.match(document.body[k])
2764 angle = get_value(document.body, 'rotateAngle', i, j)
2765 width = get_value(document.body, 'width', i, j)
2766 height = get_value(document.body, 'height', i, j)
2767 scale = get_value(document.body, 'scale', i, j)
2768 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2772 options += ",angle=" + angle
2774 options += "angle=" + angle
2777 options += ",width=" + convert_len(width)
2779 options += "width=" + convert_len(width)
2782 options += ",height=" + convert_len(height)
2784 options += "height=" + convert_len(height)
2787 options += ",scale=" + scale
2789 options += "scale=" + scale
2790 if keepAspectRatio != '':
2792 options += ",keepaspectratio"
2794 options += "keepaspectratio"
2796 options = '[' + options + ']'
2797 del document.body[i+1:j+1]
2798 document.body[i:i+1] = ['\\begin_inset ERT',
2801 '\\begin_layout Standard',
2804 'includepdf' + options + '{' + filename + '}',
2808 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2814 def revert_mexican(document):
2815 ' Set language Spanish(Mexico) to Spanish '
2817 if document.language == "spanish-mexico":
2818 document.language = "spanish"
2819 i = find_token(document.header, "\\language", 0)
2821 document.header[i] = "\\language spanish"
2824 j = find_token(document.body, "\\lang spanish-mexico", j)
2827 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2831 def remove_embedding(document):
2832 ' Remove embed tag from all insets '
2833 revert_inset_embedding(document, 'Graphics')
2834 revert_inset_embedding(document, 'External')
2835 revert_inset_embedding(document, 'CommandInset include')
2836 revert_inset_embedding(document, 'CommandInset bibtex')
2839 def revert_master(document):
2840 ' Remove master param '
2841 i = find_token(document.header, "\\master", 0)
2843 del document.header[i]
2846 def revert_graphics_group(document):
2847 ' Revert group information from graphics insets '
2850 i = find_token(document.body, "\\begin_inset Graphics", i)
2853 j = find_end_of_inset(document.body, i)
2855 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2858 k = find_token(document.body, " groupId", i, j)
2862 del document.body[k]
2866 def update_apa_styles(document):
2867 ' Replace obsolete styles '
2869 if document.textclass != "apa":
2872 obsoletedby = { "Acknowledgments": "Acknowledgements",
2873 "Section*": "Section",
2874 "Subsection*": "Subsection",
2875 "Subsubsection*": "Subsubsection",
2876 "Paragraph*": "Paragraph",
2877 "Subparagraph*": "Subparagraph"}
2880 i = find_token(document.body, "\\begin_layout", i)
2884 layout = document.body[i][14:]
2885 if layout in obsoletedby:
2886 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2891 def convert_paper_sizes(document):
2892 ' exchange size options legalpaper and executivepaper to correct order '
2893 # routine is needed to fix http://www.lyx.org/trac/ticket/4868
2896 i = find_token(document.header, "\\papersize executivepaper", 0)
2898 document.header[i] = "\\papersize legalpaper"
2900 j = find_token(document.header, "\\papersize legalpaper", 0)
2902 document.header[j] = "\\papersize executivepaper"
2905 def revert_paper_sizes(document):
2906 ' exchange size options legalpaper and executivepaper to correct order '
2909 i = find_token(document.header, "\\papersize executivepaper", 0)
2911 document.header[i] = "\\papersize legalpaper"
2913 j = find_token(document.header, "\\papersize legalpaper", 0)
2915 document.header[j] = "\\papersize executivepaper"
2918 def convert_InsetSpace(document):
2919 " Convert '\\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 revert_InsetSpace(document):
2929 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2932 i = find_token(document.body, "\\begin_inset space", i)
2935 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2938 def convert_display_enum(document):
2939 " Convert 'display foo' to 'display false/true'"
2942 i = find_token(document.body, "\tdisplay", i)
2945 val = get_value(document.body, 'display', i)
2947 document.body[i] = document.body[i].replace('none', 'false')
2948 if val == "default":
2949 document.body[i] = document.body[i].replace('default', 'true')
2950 if val == "monochrome":
2951 document.body[i] = document.body[i].replace('monochrome', 'true')
2952 if val == "grayscale":
2953 document.body[i] = document.body[i].replace('grayscale', 'true')
2955 document.body[i] = document.body[i].replace('color', 'true')
2956 if val == "preview":
2957 document.body[i] = document.body[i].replace('preview', 'true')
2961 def revert_display_enum(document):
2962 " Revert 'display false/true' to 'display none/color'"
2965 i = find_token(document.body, "\tdisplay", i)
2968 val = get_value(document.body, 'display', i)
2970 document.body[i] = document.body[i].replace('false', 'none')
2972 document.body[i] = document.body[i].replace('true', 'default')
2976 def remove_fontsCJK(document):
2977 ' Remove font_cjk param '
2978 i = find_token(document.header, "\\font_cjk", 0)
2980 del document.header[i]
2983 def convert_plain_layout(document):
2984 " Convert 'PlainLayout' to 'Plain Layout'"
2987 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2990 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2991 '\\begin_layout Plain Layout')
2995 def revert_plain_layout(document):
2996 " Revert 'Plain Layout' to 'PlainLayout'"
2999 i = find_token(document.body, '\\begin_layout Plain Layout', i)
3002 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
3003 '\\begin_layout PlainLayout')
3007 def revert_plainlayout(document):
3008 " Revert 'PlainLayout' to 'Standard'"
3011 i = find_token(document.body, '\\begin_layout PlainLayout', i)
3014 # This will be incorrect for some document classes, since Standard is not always
3015 # the default. But (a) it is probably the best we can do and (b) it will actually
3016 # work, in fact, since an unknown layout will be converted to default.
3017 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
3018 '\\begin_layout Standard')
3022 def revert_polytonicgreek(document):
3023 "Set language polytonic Greek to Greek"
3025 if document.language == "polutonikogreek":
3026 document.language = "greek"
3027 i = find_token(document.header, "\\language", 0)
3029 document.header[i] = "\\language greek"
3032 j = find_token(document.body, "\\lang polutonikogreek", j)
3035 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
3039 def revert_removed_modules(document):
3042 i = find_token(document.header, "\\begin_remove_modules", i)
3045 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
3047 # this should not happen
3049 document.header[i : j + 1] = []
3052 def add_plain_layout(document):
3055 i = find_token(document.body, "\\begin_layout", i)
3058 if len(document.body[i].split()) == 1:
3059 document.body[i] = "\\begin_layout Plain Layout"
3063 def revert_tabulators(document):
3064 "Revert tabulators to 4 spaces"
3067 i = find_token(document.body, "\t", i)
3070 document.body[i] = document.body[i].replace("\t", " ")
3074 def revert_tabsize(document):
3075 "Revert the tabsize parameter of listings"
3079 # either it is the only parameter
3080 i = find_token(document.body, 'lstparams "tabsize=4"', i)
3082 del document.body[i]
3084 j = find_token(document.body, "lstparams", j)
3087 pos = document.body[j].find(",tabsize=")
3088 document.body[j] = document.body[j][:pos] + '"'
3093 def revert_mongolian(document):
3094 "Set language Mongolian to English"
3096 if document.language == "mongolian":
3097 document.language = "english"
3098 i = find_token(document.header, "\\language", 0)
3100 document.header[i] = "\\language english"
3103 j = find_token(document.body, "\\lang mongolian", j)
3106 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
3110 def revert_default_options(document):
3111 ' Remove param use_default_options '
3112 i = find_token(document.header, "\\use_default_options", 0)
3114 del document.header[i]
3117 def convert_default_options(document):
3118 ' Add param use_default_options and set it to false '
3119 i = find_token(document.header, "\\textclass", 0)
3121 document.warning("Malformed LyX document: Missing `\\textclass'.")
3123 document.header.insert(i, '\\use_default_options false')
3126 def revert_backref_options(document):
3127 ' Revert option pdf_backref=page to pagebackref '
3128 i = find_token(document.header, "\\pdf_backref page", 0)
3130 document.header[i] = "\\pdf_pagebackref true"
3133 def convert_backref_options(document):
3134 ' We have changed the option pagebackref to backref=true '
3135 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3137 document.header[i] = "\\pdf_backref page"
3138 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3140 del document.header[j]
3141 # backref=true was not a valid option, we meant backref=section
3142 k = find_token(document.header, "\\pdf_backref true", 0)
3143 if k != -1 and i != -1:
3144 del document.header[k]
3145 elif k != -1 and j != -1:
3146 document.header[k] = "\\pdf_backref section"
3149 def convert_charstyle_element(document):
3150 "Convert CharStyle to Element for docbook backend"
3151 if document.backend != "docbook":
3155 i = find_token(document.body, "\\begin_inset Flex CharStyle:", i)
3158 document.body[i] = document.body[i].replace('\\begin_inset Flex CharStyle:',
3159 '\\begin_inset Flex Element:')
3161 def revert_charstyle_element(document):
3162 "Convert Element to CharStyle for docbook backend"
3163 if document.backend != "docbook":
3167 i = find_token(document.body, "\\begin_inset Flex Element:", i)
3170 document.body[i] = document.body[i].replace('\\begin_inset Flex Element:',
3171 '\\begin_inset Flex CharStyle:')
3177 supported_versions = ["1.6.0","1.6"]
3178 convert = [[277, [fix_wrong_tables]],
3179 [278, [close_begin_deeper]],
3180 [279, [long_charstyle_names]],
3181 [280, [axe_show_label]],
3184 [283, [convert_flex]],
3188 [287, [convert_wrapfig_options]],
3189 [288, [convert_inset_command]],
3190 [289, [convert_latexcommand_index]],
3193 [292, [convert_japanese_cjk]],
3195 [294, [convert_pdf_options]],
3196 [295, [convert_htmlurl, convert_url]],
3197 [296, [convert_include]],
3198 [297, [convert_usorbian]],
3199 [298, [convert_macro_global]],
3204 [303, [convert_serbocroatian]],
3205 [304, [convert_framed_notes]],
3212 [311, [convert_ams_classes]],
3214 [313, [convert_module_names]],
3217 [316, [convert_subfig]],
3220 [319, [convert_spaceinset, convert_hfill]],
3222 [321, [convert_tablines]],
3223 [322, [convert_plain_layout]],
3224 [323, [convert_pagebreaks]],
3225 [324, [convert_linebreaks]],
3226 [325, [convert_japanese_plain]],
3229 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3232 [331, [convert_ltcaption]],
3234 [333, [update_apa_styles]],
3235 [334, [convert_paper_sizes]],
3236 [335, [convert_InsetSpace]],
3238 [337, [convert_display_enum]],
3241 [340, [add_plain_layout]],
3244 [343, [convert_default_options]],
3245 [344, [convert_backref_options]],
3246 [345, [convert_charstyle_element]]
3249 revert = [[344, [revert_charstyle_element]],
3250 [343, [revert_backref_options]],
3251 [342, [revert_default_options]],
3252 [341, [revert_mongolian]],
3253 [340, [revert_tabulators, revert_tabsize]],
3255 [338, [revert_removed_modules]],
3256 [337, [revert_polytonicgreek]],
3257 [336, [revert_display_enum]],
3258 [335, [remove_fontsCJK]],
3259 [334, [revert_InsetSpace]],
3260 [333, [revert_paper_sizes]],
3262 [331, [revert_graphics_group]],
3263 [330, [revert_ltcaption]],
3264 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
3265 [328, [revert_master]],
3267 [326, [revert_mexican]],
3268 [325, [revert_pdfpages]],
3270 [323, [revert_linebreaks]],
3271 [322, [revert_pagebreaks]],
3272 [321, [revert_local_layout, revert_plain_layout]],
3273 [320, [revert_tablines]],
3274 [319, [revert_protected_hfill]],
3275 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3276 [317, [remove_extra_embedded_files]],
3277 [316, [revert_wrapplacement]],
3278 [315, [revert_subfig]],
3279 [314, [revert_colsep, revert_plainlayout]],
3281 [312, [revert_module_names]],
3282 [311, [revert_rotfloat, revert_widesideways]],
3283 [310, [revert_external_embedding]],
3284 [309, [revert_btprintall]],
3285 [308, [revert_nocite]],
3286 [307, [revert_serbianlatin]],
3287 [306, [revert_slash, revert_nobreakdash]],
3288 [305, [revert_interlingua]],
3289 [304, [revert_bahasam]],
3290 [303, [revert_framed_notes]],
3292 [301, [revert_latin, revert_samin]],
3293 [300, [revert_linebreak]],
3294 [299, [revert_pagebreak]],
3295 [298, [revert_hyperlinktype]],
3296 [297, [revert_macro_optional_params]],
3297 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3298 [295, [revert_include]],
3299 [294, [revert_href, revert_url]],
3300 [293, [revert_pdf_options_2]],
3301 [292, [revert_inset_info]],
3302 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3303 [290, [revert_vietnamese]],
3304 [289, [revert_wraptable]],
3305 [288, [revert_latexcommand_index]],
3306 [287, [revert_inset_command]],
3307 [286, [revert_wrapfig_options]],
3308 [285, [revert_pdf_options]],
3309 [284, [remove_inzip_options]],
3311 [282, [revert_flex]],
3313 [280, [revert_begin_modules]],
3314 [279, [revert_show_label]],
3315 [278, [revert_long_charstyle_names]],
3321 if __name__ == "__main__":