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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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, get_value_string
27 ####################################################################
28 # Private helper functions
30 def find_end_of_inset(lines, i):
31 " Find end of inset, where lines[i] is included."
32 return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
36 # document.body[i] = wrap_insert_ert(...)
37 # wrap_into_ert may returns a multiline string, which should NOT appear
38 # in document.body. Insetad, do something like this:
39 # subst = wrap_inset_ert(...)
40 # subst = subst.split('\n')
41 # document.body[i:i+1] = subst
43 # where the last statement resets the counter to accord with the added
45 def wrap_into_ert(string, src, dst):
46 '''Within string, replace occurrences of src with dst, wrapped into ERT
47 E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is:
48 sch<ERT>\\backslash</ERT>"on'''
49 return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
50 + dst + '\n\\end_layout\n\\end_inset\n')
52 def put_cmd_in_ert(string):
53 string = string.replace('\\', "\\backslash\n")
54 string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n" \
55 + string + "\n\\end_layout\n\\end_inset"
58 def add_to_preamble(document, text):
59 """ Add text to the preamble if it is not already there.
60 Only the first line is checked!"""
62 if find_token(document.preamble, text[0], 0) != -1:
65 document.preamble.extend(text)
67 def insert_to_preamble(index, document, text):
68 """ Insert text to the preamble at a given line"""
70 document.preamble.insert(index, text)
72 # Convert a LyX length into a LaTeX length
74 units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
75 "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
76 "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
78 # Convert LyX units to LaTeX units
79 for unit in units.keys():
80 if len.find(unit) != -1:
81 len = '%f' % (len2value(len) / 100)
82 len = len.strip('0') + units[unit]
87 # Return the value of len without the unit in numerical form.
89 result = re.search('([+-]?[0-9.]+)', len)
91 return float(result.group(1))
95 # Unfortunately, this doesn't really work, since Standard isn't always default.
96 # But it's as good as we can do right now.
97 def find_default_layout(document, start, end):
98 l = find_token(document.body, "\\begin_layout Standard", start, end)
100 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
102 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
105 def get_option(document, m, option, default):
106 l = document.body[m].find(option)
109 val = document.body[m][l:].split('"')[1]
112 def remove_option(document, m, option):
113 l = document.body[m].find(option)
115 val = document.body[m][l:].split('"')[1]
116 document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
119 def set_option(document, m, option, value):
120 l = document.body[m].find(option)
122 oldval = document.body[m][l:].split('"')[1]
123 l = l + len(option + '="')
124 document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
126 document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
130 def read_unicodesymbols():
131 " Read the unicodesymbols list of unicode characters and corresponding commands."
132 pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
133 fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
135 # Two backslashes, followed by some non-word character, and then a character
136 # in brackets. The idea is to check for constructs like: \"{u}, which is how
137 # they are written in the unicodesymbols file; but they can also be written
139 r = re.compile(r'\\\\(\W)\{(\w)\}')
140 for line in fp.readlines():
141 if line[0] != '#' and line.strip() != "":
142 line=line.replace(' "',' ') # remove all quotation marks with spaces before
143 line=line.replace('" ',' ') # remove all quotation marks with spaces after
144 line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
146 [ucs4,command,dead] = line.split(None,2)
147 if command[0:1] != "\\":
149 spec_chars.append([command, unichr(eval(ucs4))])
155 # If the character is a double-quote, then we need to escape it, too,
156 # since it is done that way in the LyX file.
157 if m.group(1) == "\"":
159 command += m.group(1) + m.group(2)
160 spec_chars.append([command, unichr(eval(ucs4))])
165 def extract_argument(line):
166 'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
171 bracere = re.compile("(\s*)(.*)")
172 n = bracere.match(line)
173 whitespace = n.group(1)
176 if brace != "[" and brace != "{":
200 # We never found the matching brace
201 # So, to be on the safe side, let's just return everything
202 # which will then get wrapped as ERT
204 return (line[:pos + 1], line[pos + 1:])
208 '''Converts LaTeX commands into ERT. line may well be a multi-line
209 string when it is returned.'''
214 ## FIXME Escaped \ ??
215 # This regex looks for a LaTeX command---i.e., something of the form
216 # "\alPhaStuFF", or "\X", where X is any character---where the command
217 # may also be preceded by an additional backslash, which is how it would
218 # appear (e.g.) in an InsetIndex.
219 labelre = re.compile(r'(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)')
221 m = labelre.match(line)
228 (arg, rest) = extract_argument(end)
233 # If we wanted to put labels into an InsetLabel, for example, then we
234 # would just need to test here for cmd == "label" and then take some
235 # appropriate action, i.e., to use arg to get the content and then
236 # wrap it appropriately.
237 cmd = put_cmd_in_ert(cmd)
238 retval += "\n" + cmd + "\n"
240 m = labelre.match(line)
246 #Might should do latex2ert first, then deal with stuff that DOESN'T
247 #end up inside ERT. That routine could be modified so that it returned
248 #a list of lines, and we could then skip ERT bits and only deal with
251 '''Takes a string, possibly multi-line, and returns the result of
252 converting LaTeX constructs into LyX constructs. Returns a list of
253 lines, suitable for insertion into document.body.'''
257 # Convert LaTeX to Unicode
258 reps = read_unicodesymbols()
259 # Commands of this sort need to be checked to make sure they are
260 # followed by a non-alpha character, lest we replace too much.
261 hardone = re.compile(r'^\\\\[a-zA-Z]+$')
264 if hardone.match(rep[0]):
267 pos = data.find(rep[0], pos)
270 nextpos = pos + len(rep[0])
271 if nextpos < len(data) and data[nextpos].isalpha():
272 # not the end of that command
275 data = data[:pos] + rep[1] + data[nextpos:]
278 data = data.replace(rep[0], rep[1])
281 data = wrap_into_ert(data, r'\"', '"')
284 mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
285 lines = data.split('\n')
287 #document.warning("LINE: " + line)
288 #document.warning(str(i) + ":" + document.body[i])
289 #document.warning("LAST: " + document.body[-1])
294 f = m.group(2).replace('\\\\', '\\')
299 subst = s.split('\n')
301 retval.append("\\begin_inset Formula " + f)
302 retval.append("\\end_inset")
304 # Handle whatever is left, which is just text
306 subst = g.split('\n')
311 def lyx2latex(document, lines):
312 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
313 # clean up multiline stuff
316 reps = read_unicodesymbols()
318 for curline in range(len(lines)):
319 line = lines[curline]
320 if line.startswith("\\begin_inset ERT"):
321 # We don't want to replace things inside ERT, so figure out
322 # where the end of the inset is.
323 ert_end = find_end_of_inset(lines, curline + 1)
325 elif line.startswith("\\begin_inset Formula"):
327 elif line.startswith("\\begin_inset Quotes"):
328 # For now, we do a very basic reversion. Someone who understands
329 # quotes is welcome to fix it up.
330 qtype = line[20:].strip()
344 elif line.isspace() or \
345 line.startswith("\\begin_layout") or \
346 line.startswith("\\end_layout") or \
347 line.startswith("\\begin_inset") or \
348 line.startswith("\\end_inset") or \
349 line.startswith("\\lang") or \
350 line.strip() == "status collapsed" or \
351 line.strip() == "status open":
355 # this needs to be added to the preamble because of cases like
356 # \textmu, \textbackslash, etc.
357 add_to_preamble(document, ['% added by lyx2lyx for converted index entries',
358 '\\@ifundefined{textmu}',
359 ' {\\usepackage{textcomp}}{}'])
360 # a lossless reversion is not possible
361 # try at least to handle some common insets and settings
362 if ert_end >= curline:
363 line = line.replace(r'\backslash', r'\\')
365 line = line.replace('&', '\\&{}')
366 line = line.replace('#', '\\#{}')
367 line = line.replace('^', '\\^{}')
368 line = line.replace('%', '\\%{}')
369 line = line.replace('_', '\\_{}')
370 line = line.replace('$', '\\${}')
372 # Do the LyX text --> LaTeX conversion
374 line = line.replace(rep[1], rep[0] + "{}")
375 line = line.replace(r'\backslash', r'\textbackslash{}')
376 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
377 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
378 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
379 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
380 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
381 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
382 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
383 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
384 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
389 ####################################################################
391 def convert_ltcaption(document):
394 i = find_token(document.body, "\\begin_inset Tabular", i)
397 j = find_end_of_inset(document.body, i + 1)
399 document.warning("Malformed LyX document: Could not find end of tabular.")
402 nrows = int(document.body[i+1].split('"')[3])
403 ncols = int(document.body[i+1].split('"')[5])
406 for k in range(nrows):
407 m = find_token(document.body, "<row", m)
410 for k in range(ncols):
411 m = find_token(document.body, "<cell", m)
413 mend = find_token(document.body, "</cell>", m + 1)
414 # first look for caption insets
415 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
416 # then look for ERT captions
418 mcap = find_token(document.body, "caption", m + 1, mend)
420 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
423 if caption == 'true':
425 set_option(document, r, 'caption', 'true')
426 set_option(document, m, 'multicolumn', '1')
427 set_option(document, m, 'bottomline', 'false')
428 set_option(document, m, 'topline', 'false')
429 set_option(document, m, 'rightline', 'false')
430 set_option(document, m, 'leftline', 'false')
431 #j = find_end_of_inset(document.body, j + 1)
433 set_option(document, m, 'multicolumn', '2')
440 #FIXME Use of wrap_into_ert can confuse lyx2lyx
441 def revert_ltcaption(document):
444 i = find_token(document.body, "\\begin_inset Tabular", i)
447 j = find_end_of_inset(document.body, i + 1)
449 document.warning("Malformed LyX document: Could not find end of tabular.")
453 nrows = int(document.body[i+1].split('"')[3])
454 ncols = int(document.body[i+1].split('"')[5])
456 for k in range(nrows):
457 m = find_token(document.body, "<row", m)
458 caption = get_option(document, m, 'caption', 'false')
459 if caption == 'true':
460 remove_option(document, m, 'caption')
461 for k in range(ncols):
462 m = find_token(document.body, "<cell", m)
463 remove_option(document, m, 'multicolumn')
465 m = find_token(document.body, "\\begin_inset Caption", m)
468 m = find_end_of_inset(document.body, m + 1)
469 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
475 def convert_tablines(document):
478 i = find_token(document.body, "\\begin_inset Tabular", i)
480 # LyX 1.3 inserted an extra space between \begin_inset
481 # and Tabular so let us try if this is the case and fix it.
482 i = find_token(document.body, "\\begin_inset Tabular", i)
486 document.body[i] = "\\begin_inset Tabular"
487 j = find_end_of_inset(document.body, i + 1)
489 document.warning("Malformed LyX document: Could not find end of tabular.")
493 nrows = int(document.body[i+1].split('"')[3])
494 ncols = int(document.body[i+1].split('"')[5])
497 for k in range(ncols):
498 m = find_token(document.body, "<column", m)
499 left = get_option(document, m, 'leftline', 'false')
500 right = get_option(document, m, 'rightline', 'false')
501 col_info.append([left, right])
502 remove_option(document, m, 'leftline')
503 remove_option(document, m, 'rightline')
507 for k in range(nrows):
508 m = find_token(document.body, "<row", m)
509 top = get_option(document, m, 'topline', 'false')
510 bottom = get_option(document, m, 'bottomline', 'false')
511 row_info.append([top, bottom])
512 remove_option(document, m, 'topline')
513 remove_option(document, m, 'bottomline')
518 for k in range(nrows*ncols):
519 m = find_token(document.body, "<cell", m)
520 mc_info.append(get_option(document, m, 'multicolumn', '0'))
523 for l in range(nrows):
524 for k in range(ncols):
525 m = find_token(document.body, '<cell', m)
526 if mc_info[l*ncols + k] == '0':
527 r = set_option(document, m, 'topline', row_info[l][0])
528 r = set_option(document, m, 'bottomline', row_info[l][1])
529 r = set_option(document, m, 'leftline', col_info[k][0])
530 r = set_option(document, m, 'rightline', col_info[k][1])
531 elif mc_info[l*ncols + k] == '1':
533 while s < ncols and mc_info[l*ncols + s] == '2':
535 if s < ncols and mc_info[l*ncols + s] != '1':
536 r = set_option(document, m, 'rightline', col_info[k][1])
537 if k > 0 and mc_info[l*ncols + k - 1] == '0':
538 r = set_option(document, m, 'leftline', col_info[k][0])
543 def revert_tablines(document):
546 i = find_token(document.body, "\\begin_inset Tabular", i)
549 j = find_end_of_inset(document.body, i + 1)
551 document.warning("Malformed LyX document: Could not find end of tabular.")
555 nrows = int(document.body[i+1].split('"')[3])
556 ncols = int(document.body[i+1].split('"')[5])
559 for k in range(nrows*ncols):
560 m = find_token(document.body, "<cell", m)
561 top = get_option(document, m, 'topline', 'false')
562 bottom = get_option(document, m, 'bottomline', 'false')
563 left = get_option(document, m, 'leftline', 'false')
564 right = get_option(document, m, 'rightline', 'false')
565 lines.append([top, bottom, left, right])
568 # we will want to ignore longtable captions
571 for k in range(nrows):
572 m = find_token(document.body, "<row", m)
573 caption = get_option(document, m, 'caption', 'false')
574 caption_info.append([caption])
579 for k in range(ncols):
580 m = find_token(document.body, "<column", m)
582 for l in range(nrows):
583 left = lines[l*ncols + k][2]
584 if left == 'false' and caption_info[l] == 'false':
586 set_option(document, m, 'leftline', left)
588 for l in range(nrows):
589 right = lines[l*ncols + k][3]
590 if right == 'false' and caption_info[l] == 'false':
592 set_option(document, m, 'rightline', right)
596 for k in range(nrows):
597 m = find_token(document.body, "<row", m)
599 for l in range(ncols):
600 top = lines[k*ncols + l][0]
603 if caption_info[k] == 'false':
605 set_option(document, m, 'topline', top)
607 for l in range(ncols):
608 bottom = lines[k*ncols + l][1]
609 if bottom == 'false':
611 if caption_info[k] == 'false':
613 set_option(document, m, 'bottomline', bottom)
619 def fix_wrong_tables(document):
622 i = find_token(document.body, "\\begin_inset Tabular", i)
625 j = find_end_of_inset(document.body, i + 1)
627 document.warning("Malformed LyX document: Could not find end of tabular.")
631 nrows = int(document.body[i+1].split('"')[3])
632 ncols = int(document.body[i+1].split('"')[5])
634 for l in range(nrows):
636 for k in range(ncols):
637 m = find_token(document.body, '<cell', m)
639 if document.body[m].find('multicolumn') != -1:
640 multicol_cont = int(document.body[m].split('"')[1])
642 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
643 document.body[m] = document.body[m][:5] + document.body[m][21:]
646 prev_multicolumn = multicol_cont
653 def close_begin_deeper(document):
657 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
662 if document.body[i][:13] == "\\begin_deeper":
669 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
672 def long_charstyle_names(document):
675 i = find_token(document.body, "\\begin_inset CharStyle", i)
678 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
681 def revert_long_charstyle_names(document):
684 i = find_token(document.body, "\\begin_inset CharStyle", i)
687 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
691 def axe_show_label(document):
694 i = find_token(document.body, "\\begin_inset CharStyle", i)
697 if document.body[i + 1].find("show_label") != -1:
698 if document.body[i + 1].find("true") != -1:
699 document.body[i + 1] = "status open"
700 del document.body[ i + 2]
702 if document.body[i + 1].find("false") != -1:
703 document.body[i + 1] = "status collapsed"
704 del document.body[ i + 2]
706 document.warning("Malformed LyX document: show_label neither false nor true.")
708 document.warning("Malformed LyX document: show_label missing in CharStyle.")
713 def revert_show_label(document):
716 i = find_token(document.body, "\\begin_inset CharStyle", i)
719 if document.body[i + 1].find("status open") != -1:
720 document.body.insert(i + 1, "show_label true")
722 if document.body[i + 1].find("status collapsed") != -1:
723 document.body.insert(i + 1, "show_label false")
725 document.warning("Malformed LyX document: no legal status line in CharStyle.")
728 def revert_begin_modules(document):
731 i = find_token(document.header, "\\begin_modules", i)
734 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
736 # this should not happen
738 document.header[i : j + 1] = []
740 def convert_flex(document):
741 "Convert CharStyle to Flex"
744 i = find_token(document.body, "\\begin_inset CharStyle", i)
747 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
749 def revert_flex(document):
750 "Convert Flex to CharStyle"
753 i = find_token(document.body, "\\begin_inset Flex", i)
756 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
759 # Discard PDF options for hyperref
760 def revert_pdf_options(document):
761 "Revert PDF options for hyperref."
762 # store the PDF options and delete the entries from the Lyx file
770 bookmarksnumbered = ""
772 bookmarksopenlevel = ""
780 i = find_token(document.header, "\\use_hyperref", i)
782 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
783 del document.header[i]
784 i = find_token(document.header, "\\pdf_store_options", i)
786 del document.header[i]
787 i = find_token(document.header, "\\pdf_title", 0)
789 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
790 title = ' pdftitle={' + title + '}'
791 del document.header[i]
792 i = find_token(document.header, "\\pdf_author", 0)
794 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
796 author = ' pdfauthor={' + author + '}'
798 author = ',\n pdfauthor={' + author + '}'
799 del document.header[i]
800 i = find_token(document.header, "\\pdf_subject", 0)
802 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
803 if title == "" and author == "":
804 subject = ' pdfsubject={' + subject + '}'
806 subject = ',\n pdfsubject={' + subject + '}'
807 del document.header[i]
808 i = find_token(document.header, "\\pdf_keywords", 0)
810 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
811 if title == "" and author == "" and subject == "":
812 keywords = ' pdfkeywords={' + keywords + '}'
814 keywords = ',\n pdfkeywords={' + keywords + '}'
815 del document.header[i]
816 i = find_token(document.header, "\\pdf_bookmarks", 0)
818 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
819 bookmarks = ',\n bookmarks=' + bookmarks
820 del document.header[i]
821 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
823 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
824 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
825 del document.header[i]
826 i = find_token(document.header, "\\pdf_bookmarksopen", i)
828 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
829 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
830 del document.header[i]
831 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
833 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
834 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
835 del document.header[i]
836 i = find_token(document.header, "\\pdf_breaklinks", i)
838 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
839 breaklinks = ',\n breaklinks=' + breaklinks
840 del document.header[i]
841 i = find_token(document.header, "\\pdf_pdfborder", i)
843 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
844 if pdfborder == 'true':
845 pdfborder = ',\n pdfborder={0 0 0}'
847 pdfborder = ',\n pdfborder={0 0 1}'
848 del document.header[i]
849 i = find_token(document.header, "\\pdf_colorlinks", i)
851 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
852 colorlinks = ',\n colorlinks=' + colorlinks
853 del document.header[i]
854 i = find_token(document.header, "\\pdf_backref", i)
856 backref = get_value_string(document.header, '\\pdf_backref', 0)
857 backref = ',\n backref=' + backref
858 del document.header[i]
859 i = find_token(document.header, "\\pdf_pagebackref", i)
861 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
862 pagebackref = ',\n pagebackref=' + pagebackref
863 del document.header[i]
864 i = find_token(document.header, "\\pdf_pagemode", 0)
866 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
867 pagemode = ',\n pdfpagemode=' + pagemode
868 del document.header[i]
869 i = find_token(document.header, "\\pdf_quoted_options", 0)
871 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
872 if title == "" and author == "" and subject == "" and keywords == "":
873 otheroptions = ' ' + otheroptions
875 otheroptions = ',\n ' + otheroptions
876 del document.header[i]
878 # write to the preamble when hyperref was used
880 # preamble write preparations
881 # bookmark numbers are only output when they are turned on
882 if bookmarksopen == ',\n bookmarksopen=true':
883 bookmarksopen = bookmarksopen + bookmarksopenlevel
884 if bookmarks == ',\n bookmarks=true':
885 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
887 bookmarks = bookmarks
888 # hypersetup is only output when there are things to be set up
889 setupstart = '\\hypersetup{%\n'
891 if otheroptions == "" and title == "" and author == ""\
892 and subject == "" and keywords == "":
896 # babel must be loaded before hyperref and hyperref the first part
897 # of the preamble, like in LyX 1.6
898 insert_to_preamble(0, document,
899 '% Commands inserted by lyx2lyx for PDF properties\n'
900 + '\\usepackage{babel}\n'
901 + '\\usepackage[unicode=true'
920 def remove_inzip_options(document):
921 "Remove inzipName and embed options from the Graphics inset"
924 i = find_token(document.body, "\\begin_inset Graphics", i)
927 j = find_end_of_inset(document.body, i + 1)
930 document.warning("Malformed LyX document: Could not find end of graphics inset.")
931 # If there's a inzip param, just remove that
932 k = find_token(document.body, "\tinzipName", i + 1, j)
935 # embed option must follow the inzipName option
936 del document.body[k+1]
940 def convert_inset_command(document):
943 \begin_inset LatexCommand cmd
945 \begin_inset CommandInset InsetType
950 i = find_token(document.body, "\\begin_inset LatexCommand", i)
953 line = document.body[i]
954 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
958 #this is adapted from factory.cpp
959 if cmdName[0:4].lower() == "cite":
960 insetName = "citation"
961 elif cmdName == "url" or cmdName == "htmlurl":
963 elif cmdName[-3:] == "ref":
965 elif cmdName == "tableofcontents":
967 elif cmdName == "printnomenclature":
968 insetName = "nomencl_print"
969 elif cmdName == "printindex":
970 insetName = "index_print"
973 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
974 document.body[i : i+1] = insertion
977 def revert_inset_command(document):
980 \begin_inset CommandInset InsetType
983 \begin_inset LatexCommand cmd
984 Some insets may end up being converted to insets earlier versions of LyX
985 will not be able to recognize. Not sure what to do about that.
989 i = find_token(document.body, "\\begin_inset CommandInset", i)
992 nextline = document.body[i+1]
993 r = re.compile(r'LatexCommand\s+(.*)$')
994 m = r.match(nextline)
996 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
999 insertion = ["\\begin_inset LatexCommand " + cmdName]
1000 document.body[i : i+2] = insertion
1003 def convert_wrapfig_options(document):
1004 "Convert optional options for wrap floats (wrapfig)."
1005 # adds the tokens "lines", "placement", and "overhang"
1008 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1011 document.body.insert(i + 1, "lines 0")
1012 j = find_token(document.body, "placement", i)
1013 # placement can be already set or not; if not, set it
1015 document.body.insert(i + 3, "overhang 0col%")
1017 document.body.insert(i + 2, "placement o")
1018 document.body.insert(i + 3, "overhang 0col%")
1022 def revert_wrapfig_options(document):
1023 "Revert optional options for wrap floats (wrapfig)."
1026 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1029 j = find_end_of_inset(document.body, i)
1031 document.warning("Can't find end of Wrap inset at line " + str(i))
1034 k = find_default_layout(document, i, j)
1036 document.warning("Can't find default layout for Wrap figure!")
1039 # Options should be between i and k now
1040 l = find_token(document.body, "lines", i, k)
1042 document.warning("Can't find lines option for Wrap figure!")
1045 m = find_token(document.body, "overhang", i + 1, k)
1047 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1050 # Do these in reverse order
1051 del document.body[m]
1052 del document.body[l]
1056 def convert_latexcommand_index(document):
1057 "Convert from LatexCommand form to collapsable form."
1059 r1 = re.compile('name "(.*)"')
1061 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1064 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1066 j = find_end_of_inset(document.body, i + 2)
1068 document.warning("Unable to find end of index inset at line " + i + "!")
1071 m = r1.match(document.body[i + 2])
1073 document.warning("Unable to match: " + document.body[i+2])
1074 # this can happen with empty index insets!
1077 fullcontent = m.group(1)
1078 linelist = latex2lyx(fullcontent)
1079 #document.warning(fullcontent)
1081 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1082 linelist + ["\\end_layout"]
1083 document.body[i : j] = linelist
1084 i += len(linelist) - (j - i)
1087 def revert_latexcommand_index(document):
1088 "Revert from collapsable form to LatexCommand form."
1091 i = find_token(document.body, "\\begin_inset Index", i)
1094 j = find_end_of_inset(document.body, i + 1)
1098 content = lyx2latex(document, document.body[i:j])
1100 content = content.replace('"', r'\"')
1101 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1102 "name " + '"' + content + '"', ""]
1106 def revert_wraptable(document):
1107 "Revert wrap table to wrap figure."
1110 i = find_token(document.body, "\\begin_inset Wrap table", i)
1113 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1117 def revert_vietnamese(document):
1118 "Set language Vietnamese to English"
1119 # Set document language from Vietnamese to English
1121 if document.language == "vietnamese":
1122 document.language = "english"
1123 i = find_token(document.header, "\\language", 0)
1125 document.header[i] = "\\language english"
1128 j = find_token(document.body, "\\lang vietnamese", j)
1131 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1135 def convert_japanese_cjk(document):
1136 "Set language japanese to japanese-cjk"
1137 # Set document language from japanese-plain to japanese
1139 if document.language == "japanese":
1140 document.language = "japanese-cjk"
1141 i = find_token(document.header, "\\language", 0)
1143 document.header[i] = "\\language japanese-cjk"
1146 j = find_token(document.body, "\\lang japanese", j)
1149 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1153 def revert_japanese(document):
1154 "Set language japanese-plain to japanese"
1155 # Set document language from japanese-plain to japanese
1157 if document.language == "japanese-plain":
1158 document.language = "japanese"
1159 i = find_token(document.header, "\\language", 0)
1161 document.header[i] = "\\language japanese"
1164 j = find_token(document.body, "\\lang japanese-plain", j)
1167 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1171 def revert_japanese_cjk(document):
1172 "Set language japanese-cjk to japanese"
1173 # Set document language from japanese-plain to japanese
1175 if document.language == "japanese-cjk":
1176 document.language = "japanese"
1177 i = find_token(document.header, "\\language", 0)
1179 document.header[i] = "\\language japanese"
1182 j = find_token(document.body, "\\lang japanese-cjk", j)
1185 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1189 def revert_japanese_encoding(document):
1190 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1191 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1193 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1195 document.header[i] = "\\inputencoding EUC-JP"
1197 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1199 document.header[j] = "\\inputencoding JIS"
1201 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1202 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1203 document.header[k] = "\\inputencoding UTF8"
1206 def revert_inset_info(document):
1207 'Replace info inset with its content'
1210 i = find_token(document.body, '\\begin_inset Info', i)
1213 j = find_end_of_inset(document.body, i + 1)
1216 document.warning("Malformed LyX document: Could not find end of Info inset.")
1219 for k in range(i, j+1):
1220 if document.body[k].startswith("arg"):
1221 arg = document.body[k][3:].strip().strip('"')
1222 if document.body[k].startswith("type"):
1223 type = document.body[k][4:].strip().strip('"')
1224 # I think there is a newline after \\end_inset, which should be removed.
1225 if document.body[j + 1].strip() == "":
1226 document.body[i : (j + 2)] = [type + ':' + arg]
1228 document.body[i : (j + 1)] = [type + ':' + arg]
1231 def convert_pdf_options(document):
1232 # Set the pdfusetitle tag, delete the pdf_store_options,
1233 # set quotes for bookmarksopenlevel"
1234 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1236 k = find_token(document.header, "\\use_hyperref", 0)
1237 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1238 k = find_token(document.header, "\\pdf_store_options", 0)
1240 del document.header[k]
1241 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1243 document.header[i] = document.header[i].replace('"', '')
1246 def revert_pdf_options_2(document):
1247 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1248 k = find_token(document.header, "\\use_hyperref", 0)
1249 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1251 del document.header[i]
1252 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1254 values = document.header[i].split()
1255 values[1] = ' "' + values[1] + '"'
1256 document.header[i] = ''.join(values)
1259 def convert_htmlurl(document):
1260 'Convert "htmlurl" to "href" insets for docbook'
1261 if document.backend != "docbook":
1265 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1268 document.body[i] = "\\begin_inset CommandInset href"
1269 document.body[i + 1] = "LatexCommand href"
1273 def convert_url(document):
1274 'Convert url insets to url charstyles'
1275 if document.backend == "docbook":
1279 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1282 n = find_token(document.body, "name", i)
1284 # place the URL name in typewriter before the new URL insert
1285 # grab the name 'bla' from the e.g. the line 'name "bla"',
1286 # therefore start with the 6th character
1287 name = document.body[n][6:-1]
1288 newname = [name + " "]
1289 document.body[i:i] = newname
1291 j = find_token(document.body, "target", i)
1293 document.warning("Malformed LyX document: Can't find target for url inset")
1296 target = document.body[j][8:-1]
1297 k = find_token(document.body, "\\end_inset", j)
1299 document.warning("Malformed LyX document: Can't find end of url inset")
1302 newstuff = ["\\begin_inset Flex URL",
1303 "status collapsed", "",
1304 "\\begin_layout Standard",
1309 document.body[i:k] = newstuff
1312 def convert_ams_classes(document):
1313 tc = document.textclass
1314 if (tc != "amsart" and tc != "amsart-plain" and
1315 tc != "amsart-seq" and tc != "amsbook"):
1317 if tc == "amsart-plain":
1318 document.textclass = "amsart"
1319 document.set_textclass()
1320 document.add_module("Theorems (Starred)")
1322 if tc == "amsart-seq":
1323 document.textclass = "amsart"
1324 document.set_textclass()
1325 document.add_module("Theorems (AMS)")
1327 #Now we want to see if any of the environments in the extended theorems
1328 #module were used in this document. If so, we'll add that module, too.
1329 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1330 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1333 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1336 i = find_token(document.body, "\\begin_layout", i)
1339 m = r.match(document.body[i])
1341 # This is an empty layout
1342 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1346 if layouts.count(m) != 0:
1347 document.add_module("Theorems (AMS-Extended)")
1351 def revert_href(document):
1352 'Reverts hyperlink insets (href) to url insets (url)'
1355 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1358 document.body[i : i + 2] = \
1359 ["\\begin_inset CommandInset url", "LatexCommand url"]
1362 def revert_url(document):
1363 'Reverts Flex URL insets to old-style URL insets'
1366 i = find_token(document.body, "\\begin_inset Flex URL", i)
1369 j = find_end_of_inset(document.body, i)
1371 document.warning("Can't find end of inset in revert_url!")
1373 k = find_default_layout(document, i, j)
1375 document.warning("Can't find default layout in revert_url!")
1378 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1379 if l == -1 or l >= j:
1380 document.warning("Can't find end of default layout in revert_url!")
1383 # OK, so the inset's data is between lines k and l.
1384 data = " ".join(document.body[k+1:l])
1386 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1388 document.body[i:j+1] = newinset
1389 i = i + len(newinset)
1392 def convert_include(document):
1393 'Converts include insets to new format.'
1395 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1397 i = find_token(document.body, "\\begin_inset Include", i)
1400 line = document.body[i]
1401 previewline = document.body[i + 1]
1404 document.warning("Unable to match line " + str(i) + " of body!")
1410 insertion = ["\\begin_inset CommandInset include",
1411 "LatexCommand " + cmd, previewline,
1412 "filename \"" + fn + "\""]
1415 insertion.append("lstparams " + '"' + opt + '"')
1417 document.body[i : i + 2] = insertion
1421 def revert_include(document):
1422 'Reverts include insets to old format.'
1424 r0 = re.compile('preview.*')
1425 r1 = re.compile('LatexCommand (.+)')
1426 r2 = re.compile('filename "(.+)"')
1427 r3 = re.compile('lstparams "(.*)"')
1429 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1433 m = r1.match(document.body[nextline])
1435 document.warning("Malformed LyX document: No LatexCommand line for `" +
1436 document.body[i] + "' on line " + str(i) + ".")
1441 if r0.match(document.body[nextline]):
1442 previewline = document.body[nextline]
1446 m = r2.match(document.body[nextline])
1448 document.warning("Malformed LyX document: No filename line for `" + \
1449 document.body[i] + "' on line " + str(i) + ".")
1455 if (cmd == "lstinputlisting"):
1456 m = r3.match(document.body[nextline])
1458 options = m.group(1)
1461 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1463 newline += ("[" + options + "]")
1464 insertion = [newline]
1465 if previewline != "":
1466 insertion.append(previewline)
1467 document.body[i : nextline] = insertion
1471 def revert_albanian(document):
1472 "Set language Albanian to English"
1474 if document.language == "albanian":
1475 document.language = "english"
1476 i = find_token(document.header, "\\language", 0)
1478 document.header[i] = "\\language english"
1481 j = find_token(document.body, "\\lang albanian", j)
1484 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1488 def revert_lowersorbian(document):
1489 "Set language lower Sorbian to English"
1491 if document.language == "lowersorbian":
1492 document.language = "english"
1493 i = find_token(document.header, "\\language", 0)
1495 document.header[i] = "\\language english"
1498 j = find_token(document.body, "\\lang lowersorbian", j)
1501 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1505 def revert_uppersorbian(document):
1506 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1508 if document.language == "uppersorbian":
1509 document.language = "usorbian"
1510 i = find_token(document.header, "\\language", 0)
1512 document.header[i] = "\\language usorbian"
1515 j = find_token(document.body, "\\lang uppersorbian", j)
1518 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1522 def convert_usorbian(document):
1523 "Set language usorbian to uppersorbian"
1525 if document.language == "usorbian":
1526 document.language = "uppersorbian"
1527 i = find_token(document.header, "\\language", 0)
1529 document.header[i] = "\\language uppersorbian"
1532 j = find_token(document.body, "\\lang usorbian", j)
1535 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1539 def convert_macro_global(document):
1540 "Remove TeX code command \global when it is in front of a macro"
1541 # math macros are nowadays already defined \global, so that an additional
1542 # \global would make the document uncompilable, see
1543 # http://bugzilla.lyx.org/show_bug.cgi?id=5371
1546 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1547 if i != -1 and i > 13:
1548 if document.body[i-6] == "global":
1549 del document.body[i-13 : i]
1555 def revert_macro_optional_params(document):
1556 "Convert macro definitions with optional parameters into ERTs"
1557 # Stub to convert macro definitions with one or more optional parameters
1558 # into uninterpreted ERT insets
1561 def revert_hyperlinktype(document):
1562 'Reverts hyperlink type'
1566 i = find_token(document.body, "target", i)
1569 j = find_token(document.body, "type", i)
1573 del document.body[j]
1577 def revert_pagebreak(document):
1578 'Reverts pagebreak to ERT'
1581 i = find_token(document.body, "\\pagebreak", i)
1584 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1585 '\\begin_layout Standard\n\n\n\\backslash\n' \
1586 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1590 def revert_linebreak(document):
1591 'Reverts linebreak to ERT'
1594 i = find_token(document.body, "\\linebreak", i)
1597 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1598 '\\begin_layout Standard\n\n\n\\backslash\n' \
1599 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1603 def revert_latin(document):
1604 "Set language Latin to English"
1606 if document.language == "latin":
1607 document.language = "english"
1608 i = find_token(document.header, "\\language", 0)
1610 document.header[i] = "\\language english"
1613 j = find_token(document.body, "\\lang latin", j)
1616 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1620 def revert_samin(document):
1621 "Set language North Sami to English"
1623 if document.language == "samin":
1624 document.language = "english"
1625 i = find_token(document.header, "\\language", 0)
1627 document.header[i] = "\\language english"
1630 j = find_token(document.body, "\\lang samin", j)
1633 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1637 def convert_serbocroatian(document):
1638 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1640 if document.language == "serbocroatian":
1641 document.language = "croatian"
1642 i = find_token(document.header, "\\language", 0)
1644 document.header[i] = "\\language croatian"
1647 j = find_token(document.body, "\\lang serbocroatian", j)
1650 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1654 def convert_framed_notes(document):
1655 "Convert framed notes to boxes. "
1658 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1661 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1670 'height_special "totalheight"']
1671 document.body[i:i+1] = subst
1675 def convert_module_names(document):
1676 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1677 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1678 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1679 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1680 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1681 modlist = document.get_module_list()
1682 if len(modlist) == 0:
1686 if modulemap.has_key(mod):
1687 newmodlist.append(modulemap[mod])
1689 document.warning("Can't find module %s in the module map!" % mod)
1690 newmodlist.append(mod)
1691 document.set_module_list(newmodlist)
1694 def revert_module_names(document):
1695 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1696 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1697 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1698 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1699 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1700 modlist = document.get_module_list()
1701 if len(modlist) == 0:
1705 if modulemap.has_key(mod):
1706 newmodlist.append(modulemap[mod])
1708 document.warning("Can't find module %s in the module map!" % mod)
1709 newmodlist.append(mod)
1710 document.set_module_list(newmodlist)
1713 def revert_colsep(document):
1714 i = find_token(document.header, "\\columnsep", 0)
1717 colsepline = document.header[i]
1718 r = re.compile(r'\\columnsep (.*)')
1719 m = r.match(colsepline)
1721 document.warning("Malformed column separation line!")
1724 del document.header[i]
1725 #it seems to be safe to add the package even if it is already used
1726 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1728 add_to_preamble(document, pretext)
1731 def revert_framed_notes(document):
1732 "Revert framed boxes to notes. "
1735 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1739 j = find_end_of_inset(document.body, i + 1)
1742 document.warning("Malformed LyX document: Could not find end of Box inset.")
1743 k = find_token(document.body, "status", i + 1, j)
1745 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1747 status = document.body[k]
1748 l = find_default_layout(document, i + 1, j)
1750 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1752 m = find_token(document.body, "\\end_layout", i + 1, j)
1754 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1756 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1757 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1758 if ibox == -1 and pbox == -1:
1759 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1760 del document.body[i+1:k]
1762 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1763 subst1 = [document.body[l],
1764 "\\begin_inset Note Shaded",
1766 '\\begin_layout Standard']
1767 document.body[l:l + 1] = subst1
1768 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1769 document.body[m:m + 1] = subst2
1773 def revert_slash(document):
1774 'Revert \\SpecialChar \\slash{} to ERT'
1775 r = re.compile(r'\\SpecialChar \\slash{}')
1777 while i < len(document.body):
1778 m = r.match(document.body[i])
1780 subst = ['\\begin_inset ERT',
1781 'status collapsed', '',
1782 '\\begin_layout Standard',
1783 '', '', '\\backslash',
1787 document.body[i: i+1] = subst
1793 def revert_nobreakdash(document):
1794 'Revert \\SpecialChar \\nobreakdash- to ERT'
1796 while i < len(document.body):
1797 line = document.body[i]
1798 r = re.compile(r'\\SpecialChar \\nobreakdash-')
1801 subst = ['\\begin_inset ERT',
1802 'status collapsed', '',
1803 '\\begin_layout Standard', '', '',
1808 document.body[i:i+1] = subst
1810 j = find_token(document.header, "\\use_amsmath", 0)
1812 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1814 document.header[j] = "\\use_amsmath 2"
1819 #Returns number of lines added/removed
1820 def revert_nocite_key(body, start, end):
1821 'key "..." -> \nocite{...}'
1822 r = re.compile(r'^key "(.*)"')
1826 m = r.match(body[i])
1828 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1829 j += 1 # because we added a line
1830 i += 2 # skip that line
1833 j -= 1 # because we deleted a line
1834 # no need to change i, since it now points to the next line
1838 def revert_nocite(document):
1839 "Revert LatexCommand nocite to ERT"
1842 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1845 if (document.body[i+1] != "LatexCommand nocite"):
1846 # note that we already incremented i
1849 insetEnd = find_end_of_inset(document.body, i)
1851 #this should not happen
1852 document.warning("End of CommandInset citation not found in revert_nocite!")
1855 paramLocation = i + 2 #start of the inset's parameters
1857 document.body[i:i+2] = \
1858 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1859 # that added two lines
1862 #print insetEnd, document.body[i: insetEnd + 1]
1863 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1864 #print insetEnd, document.body[i: insetEnd + 1]
1865 document.body.insert(insetEnd, "\\end_layout")
1866 document.body.insert(insetEnd + 1, "")
1870 def revert_btprintall(document):
1871 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1872 i = find_token(document.header, '\\use_bibtopic', 0)
1874 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1876 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1878 while i < len(document.body):
1879 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1882 j = find_end_of_inset(document.body, i + 1)
1884 #this should not happen
1885 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1886 j = len(document.body)
1887 # this range isn't really right, but it should be OK, since we shouldn't
1888 # see more than one matching line in each inset
1890 for k in range(i, j):
1891 if (document.body[k] == 'btprint "btPrintAll"'):
1892 del document.body[k]
1893 subst = ["\\begin_inset ERT",
1894 "status collapsed", "",
1895 "\\begin_layout Standard", "",
1900 document.body[i:i] = subst
1901 addlines = addedlines + len(subst) - 1
1905 def revert_bahasam(document):
1906 "Set language Bahasa Malaysia to Bahasa Indonesia"
1908 if document.language == "bahasam":
1909 document.language = "bahasa"
1910 i = find_token(document.header, "\\language", 0)
1912 document.header[i] = "\\language bahasa"
1915 j = find_token(document.body, "\\lang bahasam", j)
1918 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1922 def revert_interlingua(document):
1923 "Set language Interlingua to English"
1925 if document.language == "interlingua":
1926 document.language = "english"
1927 i = find_token(document.header, "\\language", 0)
1929 document.header[i] = "\\language english"
1932 j = find_token(document.body, "\\lang interlingua", j)
1935 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1939 def revert_serbianlatin(document):
1940 "Set language Serbian-Latin to Croatian"
1942 if document.language == "serbian-latin":
1943 document.language = "croatian"
1944 i = find_token(document.header, "\\language", 0)
1946 document.header[i] = "\\language croatian"
1949 j = find_token(document.body, "\\lang serbian-latin", j)
1952 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
1956 def revert_rotfloat(document):
1957 " Revert sideways custom floats. "
1960 # whitespace intended (exclude \\begin_inset FloatList)
1961 i = find_token(document.body, "\\begin_inset Float ", i)
1964 line = document.body[i]
1965 r = re.compile(r'\\begin_inset Float (.*)$')
1968 document.warning("Unable to match line " + str(i) + " of body!")
1971 floattype = m.group(1)
1972 if floattype == "figure" or floattype == "table":
1975 j = find_end_of_inset(document.body, i)
1977 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
1981 if get_value(document.body, 'sideways', i, j) == "false":
1984 l = find_default_layout(document, i + 1, j)
1986 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1988 subst = ['\\begin_layout Standard',
1989 '\\begin_inset ERT',
1990 'status collapsed', '',
1991 '\\begin_layout Standard', '', '',
1993 'end{sideways' + floattype + '}',
1994 '\\end_layout', '', '\\end_inset']
1995 document.body[j : j+1] = subst
1996 addedLines = len(subst) - 1
1997 del document.body[i+1 : l]
1998 addedLines -= (l-1) - (i+1)
1999 subst = ['\\begin_inset ERT', 'status collapsed', '',
2000 '\\begin_layout Standard', '', '', '\\backslash',
2001 'begin{sideways' + floattype + '}',
2002 '\\end_layout', '', '\\end_inset', '',
2004 document.body[i : i+1] = subst
2005 addedLines += len(subst) - 1
2006 if floattype == "algorithm":
2007 add_to_preamble(document,
2008 ['% Commands inserted by lyx2lyx for sideways algorithm float',
2009 '\\usepackage{rotfloat}',
2010 '\\floatstyle{ruled}',
2011 '\\newfloat{algorithm}{tbp}{loa}',
2012 '\\floatname{algorithm}{Algorithm}'])
2014 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
2018 def revert_widesideways(document):
2019 " Revert wide sideways floats. "
2022 # whitespace intended (exclude \\begin_inset FloatList)
2023 i = find_token(document.body, '\\begin_inset Float ', i)
2026 line = document.body[i]
2027 r = re.compile(r'\\begin_inset Float (.*)$')
2030 document.warning("Unable to match line " + str(i) + " of body!")
2033 floattype = m.group(1)
2034 if floattype != "figure" and floattype != "table":
2037 j = find_end_of_inset(document.body, i)
2039 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2042 if get_value(document.body, 'sideways', i, j) == "false" or \
2043 get_value(document.body, 'wide', i, j) == "false":
2046 l = find_default_layout(document, i + 1, j)
2048 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2050 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2051 'status collapsed', '',
2052 '\\begin_layout Standard', '', '', '\\backslash',
2053 'end{sideways' + floattype + '*}',
2054 '\\end_layout', '', '\\end_inset']
2055 document.body[j : j+1] = subst
2056 addedLines = len(subst) - 1
2057 del document.body[i+1:l-1]
2058 addedLines -= (l-1) - (i+1)
2059 subst = ['\\begin_inset ERT', 'status collapsed', '',
2060 '\\begin_layout Standard', '', '', '\\backslash',
2061 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2062 '\\end_inset', '', '\\end_layout', '']
2063 document.body[i : i+1] = subst
2064 addedLines += len(subst) - 1
2065 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2069 def revert_inset_embedding(document, type):
2070 ' Remove embed tag from certain type of insets'
2073 i = find_token(document.body, "\\begin_inset %s" % type, i)
2076 j = find_end_of_inset(document.body, i)
2078 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2081 k = find_token(document.body, "\tembed", i, j)
2083 k = find_token(document.body, "embed", i, j)
2085 del document.body[k]
2089 def revert_external_embedding(document):
2090 ' Remove embed tag from external inset '
2091 revert_inset_embedding(document, 'External')
2094 def convert_subfig(document):
2095 " Convert subfigures to subfloats. "
2098 i = find_token(document.body, '\\begin_inset Graphics', i)
2101 endInset = find_end_of_inset(document.body, i)
2103 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2106 k = find_token(document.body, '\tsubcaption', i, endInset)
2110 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2112 document.warning("Malformed lyx document: Can't find subcaptionText!")
2115 caption = document.body[l][16:].strip('"')
2116 del document.body[l]
2117 del document.body[k]
2119 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2120 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2121 '', '\\begin_layout Plain Layout'] + latex2lyx(caption) + \
2122 [ '\\end_layout', '', '\\end_inset', '',
2123 '\\end_layout', '', '\\begin_layout Plain Layout']
2124 document.body[i : i] = subst
2125 addedLines += len(subst)
2126 endInset += addedLines
2127 subst = ['', '\\end_inset', '', '\\end_layout']
2128 document.body[endInset : endInset] = subst
2129 addedLines += len(subst)
2133 def revert_subfig(document):
2134 " Revert subfloats. "
2137 # whitespace intended (exclude \\begin_inset FloatList)
2138 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2144 j = find_end_of_inset(document.body, i)
2146 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2147 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2149 continue # this will get us back to the outer loop, since j == -1
2150 # look for embedded float (= subfloat)
2151 # whitespace intended (exclude \\begin_inset FloatList)
2152 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2155 # is the subfloat aligned?
2156 al = find_token(document.body, '\\align ', k - 1)
2160 if get_value(document.body, '\\align', al) == "center":
2161 alignment_beg = "\\backslash\nbegin{centering}"
2162 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2163 elif get_value(document.body, '\\align', al) == "left":
2164 alignment_beg = "\\backslash\nbegin{raggedright}"
2165 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2166 elif get_value(document.body, '\\align', al) == "right":
2167 alignment_beg = "\\backslash\nbegin{raggedleft}"
2168 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2169 l = find_end_of_inset(document.body, k)
2171 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2174 continue # escape to the outer loop
2175 m = find_default_layout(document, k + 1, l)
2177 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2182 capend = find_end_of_inset(document.body, cap)
2184 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2188 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2190 lblend = find_end_of_inset(document.body, lbl + 1)
2192 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2194 for line in document.body[lbl:lblend + 1]:
2195 if line.startswith('name '):
2196 label = line.split()[1].strip('"')
2203 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2205 optend = find_end_of_inset(document.body, opt)
2207 document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
2209 optc = find_default_layout(document, opt, optend)
2211 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2213 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2214 for line in document.body[optc:optcend]:
2215 if not line.startswith('\\'):
2216 shortcap += line.strip()
2220 for line in document.body[cap:capend]:
2221 if line in document.body[lbl:lblend]:
2223 elif line in document.body[opt:optend]:
2225 elif not line.startswith('\\'):
2226 caption += line.strip()
2228 caption += "\\backslash\nlabel{" + label + "}"
2229 subst = '\\begin_layout Plain Layout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2230 '\\begin_layout Plain Layout\n\n}' + alignment_end + \
2231 '\n\\end_layout\n\n\\end_inset\n\n' \
2232 '\\end_layout\n\n\\begin_layout Plain Layout\n'
2233 subst = subst.split('\n')
2234 document.body[l : l+1] = subst
2235 addedLines = len(subst) - 1
2236 # this is before l and so is unchanged by the multiline insertion
2238 del document.body[cap:capend+1]
2239 addedLines -= (capend + 1 - cap)
2240 del document.body[k+1:m-1]
2241 addedLines -= (m - 1 - (k + 1))
2242 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2243 '\\begin_layout Plain Layout\n\n' + alignment_beg + '\\backslash\n' \
2245 if len(shortcap) > 0:
2246 insertion = insertion + "[" + shortcap + "]"
2247 if len(caption) > 0:
2248 insertion = insertion + "[" + caption + "]"
2249 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2250 insertion = insertion.split('\n')
2251 document.body[k : k + 1] = insertion
2252 addedLines += len(insertion) - 1
2254 del document.body[al]
2256 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2260 def revert_wrapplacement(document):
2261 " Revert placement options wrap floats (wrapfig). "
2264 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2267 e = find_end_of_inset(document.body, i)
2268 j = find_token(document.body, "placement", i + 1, e)
2270 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2273 r = re.compile("placement (o|i|l|r)")
2274 m = r.match(document.body[j])
2276 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2277 document.body[j] = "placement " + m.group(1).lower()
2281 def remove_extra_embedded_files(document):
2282 " Remove \extra_embedded_files from buffer params "
2283 i = find_token(document.header, '\\extra_embedded_files', 0)
2286 document.header.pop(i)
2289 def convert_spaceinset(document):
2290 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2292 while i < len(document.body):
2293 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2297 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2298 document.body[i: i+1] = subst
2304 def revert_spaceinset(document):
2305 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2308 i = find_token(document.body, "\\begin_inset Space", i)
2311 j = find_end_of_inset(document.body, i)
2313 document.warning("Malformed LyX document: Could not find end of space inset.")
2315 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2316 del document.body[j]
2319 def convert_hfill(document):
2320 " Convert hfill to space inset "
2323 i = find_token(document.body, "\\hfill", i)
2326 subst = document.body[i].replace('\\hfill', \
2327 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2328 subst = subst.split('\n')
2329 document.body[i : i+1] = subst
2333 def revert_hfills(document):
2334 ' Revert \\hfill commands '
2335 hfill = re.compile(r'\\hfill')
2336 dotfill = re.compile(r'\\dotfill')
2337 hrulefill = re.compile(r'\\hrulefill')
2340 i = find_token(document.body, "\\InsetSpace", i)
2343 if hfill.search(document.body[i]):
2344 document.body[i] = \
2345 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2348 if dotfill.search(document.body[i]):
2349 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2350 '\\begin_inset ERT\nstatus collapsed\n\n' \
2351 '\\begin_layout Standard\n\n\n\\backslash\n' \
2352 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2353 subst = subst.split('\n')
2354 document.body[i : i+1] = subst
2357 if hrulefill.search(document.body[i]):
2358 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2359 '\\begin_inset ERT\nstatus collapsed\n\n' \
2360 '\\begin_layout Standard\n\n\n\\backslash\n' \
2361 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2362 subst = subst.split('\n')
2363 document.body[i : i+1] = subst
2368 def revert_hspace(document):
2369 ' Revert \\InsetSpace \\hspace{} to ERT '
2371 hspace = re.compile(r'\\hspace{}')
2372 hstar = re.compile(r'\\hspace\*{}')
2374 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2377 length = get_value(document.body, '\\length', i+1)
2379 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2381 del document.body[i+1]
2383 if hstar.search(document.body[i]):
2384 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2385 '\\begin_inset ERT\nstatus collapsed\n\n' \
2386 '\\begin_layout Standard\n\n\n\\backslash\n' \
2387 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2388 subst = subst.split('\n')
2389 document.body[i : i+1] = subst
2390 addedLines += len(subst) - 1
2393 if hspace.search(document.body[i]):
2394 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2395 '\\begin_inset ERT\nstatus collapsed\n\n' \
2396 '\\begin_layout Standard\n\n\n\\backslash\n' \
2397 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2398 subst = subst.split('\n')
2399 document.body[i : i+1] = subst
2400 addedLines += len(subst) - 1
2406 def revert_protected_hfill(document):
2407 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2410 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2413 j = find_end_of_inset(document.body, i)
2415 document.warning("Malformed LyX document: Could not find end of space inset.")
2417 del document.body[j]
2418 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2419 '\\begin_inset ERT\nstatus collapsed\n\n' \
2420 '\\begin_layout Standard\n\n\n\\backslash\n' \
2421 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2422 subst = subst.split('\n')
2423 document.body[i : i+1] = subst
2427 def revert_leftarrowfill(document):
2428 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2431 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2434 j = find_end_of_inset(document.body, i)
2436 document.warning("Malformed LyX document: Could not find end of space inset.")
2438 del document.body[j]
2439 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2440 '\\begin_inset ERT\nstatus collapsed\n\n' \
2441 '\\begin_layout Standard\n\n\n\\backslash\n' \
2442 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2443 subst = subst.split('\n')
2444 document.body[i : i+1] = subst
2448 def revert_rightarrowfill(document):
2449 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2452 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2455 j = find_end_of_inset(document.body, i)
2457 document.warning("Malformed LyX document: Could not find end of space inset.")
2459 del document.body[j]
2460 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2461 '\\begin_inset ERT\nstatus collapsed\n\n' \
2462 '\\begin_layout Standard\n\n\n\\backslash\n' \
2463 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2464 subst = subst.split('\n')
2465 document.body[i : i+1] = subst
2469 def revert_upbracefill(document):
2470 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2473 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2476 j = find_end_of_inset(document.body, i)
2478 document.warning("Malformed LyX document: Could not find end of space inset.")
2480 del document.body[j]
2481 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2482 '\\begin_inset ERT\nstatus collapsed\n\n' \
2483 '\\begin_layout Standard\n\n\n\\backslash\n' \
2484 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2485 subst = subst.split('\n')
2486 document.body[i : i+1] = subst
2490 def revert_downbracefill(document):
2491 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2494 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2497 j = find_end_of_inset(document.body, i)
2499 document.warning("Malformed LyX document: Could not find end of space inset.")
2501 del document.body[j]
2502 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2503 '\\begin_inset ERT\nstatus collapsed\n\n' \
2504 '\\begin_layout Standard\n\n\n\\backslash\n' \
2505 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2506 subst = subst.split('\n')
2507 document.body[i : i+1] = subst
2511 def revert_local_layout(document):
2512 ' Revert local layout headers.'
2515 i = find_token(document.header, "\\begin_local_layout", i)
2518 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2520 # this should not happen
2522 document.header[i : j + 1] = []
2525 def convert_pagebreaks(document):
2526 ' Convert inline Newpage insets to new format '
2529 i = find_token(document.body, '\\newpage', i)
2532 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2536 i = find_token(document.body, '\\pagebreak', i)
2539 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2543 i = find_token(document.body, '\\clearpage', i)
2546 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2550 i = find_token(document.body, '\\cleardoublepage', i)
2553 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2557 def revert_pagebreaks(document):
2558 ' Revert \\begin_inset Newpage to previous inline format '
2561 i = find_token(document.body, '\\begin_inset Newpage', i)
2564 j = find_end_of_inset(document.body, i)
2566 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2568 del document.body[j]
2569 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2570 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2571 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2572 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2575 def convert_linebreaks(document):
2576 ' Convert inline Newline insets to new format '
2579 i = find_token(document.body, '\\newline', i)
2582 document.body[i:i+1] = ['\\begin_inset Newline newline',
2586 i = find_token(document.body, '\\linebreak', i)
2589 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2593 def revert_linebreaks(document):
2594 ' Revert \\begin_inset Newline to previous inline format '
2597 i = find_token(document.body, '\\begin_inset Newline', i)
2600 j = find_end_of_inset(document.body, i)
2602 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2604 del document.body[j]
2605 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2606 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2609 def convert_japanese_plain(document):
2610 ' Set language japanese-plain to japanese '
2612 if document.language == "japanese-plain":
2613 document.language = "japanese"
2614 i = find_token(document.header, "\\language", 0)
2616 document.header[i] = "\\language japanese"
2619 j = find_token(document.body, "\\lang japanese-plain", j)
2622 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2626 def revert_pdfpages(document):
2627 ' Revert pdfpages external inset to ERT '
2630 i = find_token(document.body, "\\begin_inset External", i)
2633 j = find_end_of_inset(document.body, i)
2635 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2638 if get_value(document.body, 'template', i, j) == "PDFPages":
2639 filename = get_value(document.body, 'filename', i, j)
2641 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2642 for k in range(i, j):
2643 m = r.match(document.body[k])
2646 angle = get_value(document.body, 'rotateAngle', i, j)
2647 width = get_value(document.body, 'width', i, j)
2648 height = get_value(document.body, 'height', i, j)
2649 scale = get_value(document.body, 'scale', i, j)
2650 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2654 options += ",angle=" + angle
2656 options += "angle=" + angle
2659 options += ",width=" + convert_len(width)
2661 options += "width=" + convert_len(width)
2664 options += ",height=" + convert_len(height)
2666 options += "height=" + convert_len(height)
2669 options += ",scale=" + scale
2671 options += "scale=" + scale
2672 if keepAspectRatio != '':
2674 options += ",keepaspectratio"
2676 options += "keepaspectratio"
2678 options = '[' + options + ']'
2679 del document.body[i+1:j+1]
2680 document.body[i:i+1] = ['\\begin_inset ERT',
2683 '\\begin_layout Standard',
2686 'includepdf' + options + '{' + filename + '}',
2690 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2696 def revert_mexican(document):
2697 ' Set language Spanish(Mexico) to Spanish '
2699 if document.language == "spanish-mexico":
2700 document.language = "spanish"
2701 i = find_token(document.header, "\\language", 0)
2703 document.header[i] = "\\language spanish"
2706 j = find_token(document.body, "\\lang spanish-mexico", j)
2709 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2713 def remove_embedding(document):
2714 ' Remove embed tag from all insets '
2715 revert_inset_embedding(document, 'Graphics')
2716 revert_inset_embedding(document, 'External')
2717 revert_inset_embedding(document, 'CommandInset include')
2718 revert_inset_embedding(document, 'CommandInset bibtex')
2721 def revert_master(document):
2722 ' Remove master param '
2723 i = find_token(document.header, "\\master", 0)
2725 del document.header[i]
2728 def revert_graphics_group(document):
2729 ' Revert group information from graphics insets '
2732 i = find_token(document.body, "\\begin_inset Graphics", i)
2735 j = find_end_of_inset(document.body, i)
2737 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2740 k = find_token(document.body, " groupId", i, j)
2744 del document.body[k]
2748 def update_apa_styles(document):
2749 ' Replace obsolete styles '
2751 if document.textclass != "apa":
2754 obsoletedby = { "Acknowledgments": "Acknowledgements",
2755 "Section*": "Section",
2756 "Subsection*": "Subsection",
2757 "Subsubsection*": "Subsubsection",
2758 "Paragraph*": "Paragraph",
2759 "Subparagraph*": "Subparagraph"}
2762 i = find_token(document.body, "\\begin_layout", i)
2766 layout = document.body[i][14:]
2767 if layout in obsoletedby:
2768 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2773 def convert_paper_sizes(document):
2774 ' exchange size options legalpaper and executivepaper to correct order '
2775 # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2778 i = find_token(document.header, "\\papersize executivepaper", 0)
2780 document.header[i] = "\\papersize legalpaper"
2782 j = find_token(document.header, "\\papersize legalpaper", 0)
2784 document.header[j] = "\\papersize executivepaper"
2787 def revert_paper_sizes(document):
2788 ' exchange size options legalpaper and executivepaper to correct order '
2791 i = find_token(document.header, "\\papersize executivepaper", 0)
2793 document.header[i] = "\\papersize legalpaper"
2795 j = find_token(document.header, "\\papersize legalpaper", 0)
2797 document.header[j] = "\\papersize executivepaper"
2800 def convert_InsetSpace(document):
2801 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2804 i = find_token(document.body, "\\begin_inset Space", i)
2807 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2810 def revert_InsetSpace(document):
2811 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2814 i = find_token(document.body, "\\begin_inset space", i)
2817 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2820 def convert_display_enum(document):
2821 " Convert 'display foo' to 'display false/true'"
2824 i = find_token(document.body, "\tdisplay", i)
2827 val = get_value(document.body, 'display', i)
2829 document.body[i] = document.body[i].replace('none', 'false')
2830 if val == "default":
2831 document.body[i] = document.body[i].replace('default', 'true')
2832 if val == "monochrome":
2833 document.body[i] = document.body[i].replace('monochrome', 'true')
2834 if val == "grayscale":
2835 document.body[i] = document.body[i].replace('grayscale', 'true')
2837 document.body[i] = document.body[i].replace('color', 'true')
2838 if val == "preview":
2839 document.body[i] = document.body[i].replace('preview', 'true')
2843 def revert_display_enum(document):
2844 " Revert 'display false/true' to 'display none/color'"
2847 i = find_token(document.body, "\tdisplay", i)
2850 val = get_value(document.body, 'display', i)
2852 document.body[i] = document.body[i].replace('false', 'none')
2854 document.body[i] = document.body[i].replace('true', 'default')
2858 def remove_fontsCJK(document):
2859 ' Remove font_cjk param '
2860 i = find_token(document.header, "\\font_cjk", 0)
2862 del document.header[i]
2865 def convert_plain_layout(document):
2866 " Convert 'PlainLayout' to 'Plain Layout'"
2869 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2872 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2873 '\\begin_layout Plain Layout')
2877 def revert_plain_layout(document):
2878 " Convert 'PlainLayout' to 'Plain Layout'"
2881 i = find_token(document.body, '\\begin_layout Plain Layout', i)
2884 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2885 '\\begin_layout PlainLayout')
2889 def revert_plainlayout(document):
2890 " Convert 'PlainLayout' to 'Plain Layout'"
2893 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2896 # This will be incorrect for some document classes, since Standard is not always
2897 # the default. But (a) it is probably the best we can do and (b) it will actually
2898 # work, in fact, since an unknown layout will be converted to default.
2899 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2900 '\\begin_layout Standard')
2904 def revert_polytonicgreek(document):
2905 "Set language polytonic Greek to Greek"
2907 if document.language == "polutonikogreek":
2908 document.language = "greek"
2909 i = find_token(document.header, "\\language", 0)
2911 document.header[i] = "\\language greek"
2914 j = find_token(document.body, "\\lang polutonikogreek", j)
2917 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2921 def revert_removed_modules(document):
2924 i = find_token(document.header, "\\begin_remove_modules", i)
2927 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
2929 # this should not happen
2931 document.header[i : j + 1] = []
2934 def add_plain_layout(document):
2937 i = find_token(document.body, "\\begin_layout", i)
2940 if len(document.body[i].split()) == 1:
2941 document.body[i] = "\\begin_layout Plain Layout"
2945 def revert_tabulators(document):
2946 "Revert tabulators to 4 spaces"
2949 i = find_token(document.body, "\t", i)
2952 document.body[i] = document.body[i].replace("\t", " ")
2956 def revert_tabsize(document):
2957 "Revert the tabsize parameter of listings"
2961 # either it is the only parameter
2962 i = find_token(document.body, 'lstparams "tabsize=4"', i)
2964 del document.body[i]
2966 j = find_token(document.body, "lstparams", j)
2969 pos = document.body[j].find(",tabsize=")
2970 document.body[j] = document.body[j][:pos] + '"'
2975 def revert_mongolian(document):
2976 "Set language Mongolian to English"
2978 if document.language == "mongolian":
2979 document.language = "english"
2980 i = find_token(document.header, "\\language", 0)
2982 document.header[i] = "\\language english"
2985 j = find_token(document.body, "\\lang mongolian", j)
2988 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
2992 def revert_default_options(document):
2993 ' Remove param use_default_options '
2994 i = find_token(document.header, "\\use_default_options", 0)
2996 del document.header[i]
2999 def convert_default_options(document):
3000 ' Add param use_default_options and set it to false '
3001 i = find_token(document.header, "\\textclass", 0)
3003 document.warning("Malformed LyX document: Missing `\\textclass'.")
3005 document.header.insert(i, '\\use_default_options false')
3008 def revert_backref_options(document):
3009 ' Revert option pdf_backref=page to pagebackref '
3010 i = find_token(document.header, "\\pdf_backref page", 0)
3012 document.header[i] = "\\pdf_pagebackref true"
3015 def convert_backref_options(document):
3016 ' We have changed the option pagebackref to backref=true '
3017 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3019 document.header[i] = "\\pdf_backref page"
3020 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3022 del document.header[j]
3023 # backref=true was not a valid option, we meant backref=section
3024 k = find_token(document.header, "\\pdf_backref true", 0)
3025 if k != -1 and i != -1:
3026 del document.header[k]
3027 elif k != -1 and j != -1:
3028 document.header[k] = "\\pdf_backref section"
3034 supported_versions = ["1.6.0","1.6"]
3035 convert = [[277, [fix_wrong_tables]],
3036 [278, [close_begin_deeper]],
3037 [279, [long_charstyle_names]],
3038 [280, [axe_show_label]],
3041 [283, [convert_flex]],
3045 [287, [convert_wrapfig_options]],
3046 [288, [convert_inset_command]],
3047 [289, [convert_latexcommand_index]],
3050 [292, [convert_japanese_cjk]],
3052 [294, [convert_pdf_options]],
3053 [295, [convert_htmlurl, convert_url]],
3054 [296, [convert_include]],
3055 [297, [convert_usorbian]],
3056 [298, [convert_macro_global]],
3061 [303, [convert_serbocroatian]],
3062 [304, [convert_framed_notes]],
3069 [311, [convert_ams_classes]],
3071 [313, [convert_module_names]],
3074 [316, [convert_subfig]],
3077 [319, [convert_spaceinset, convert_hfill]],
3079 [321, [convert_tablines]],
3080 [322, [convert_plain_layout]],
3081 [323, [convert_pagebreaks]],
3082 [324, [convert_linebreaks]],
3083 [325, [convert_japanese_plain]],
3086 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3089 [331, [convert_ltcaption]],
3091 [333, [update_apa_styles]],
3092 [334, [convert_paper_sizes]],
3093 [335, [convert_InsetSpace]],
3095 [337, [convert_display_enum]],
3098 [340, [add_plain_layout]],
3101 [343, [convert_default_options]],
3102 [344, [convert_backref_options]]
3105 revert = [[343, [revert_backref_options]],
3106 [342, [revert_default_options]],
3107 [341, [revert_mongolian]],
3108 [340, [revert_tabulators, revert_tabsize]],
3110 [338, [revert_removed_modules]],
3111 [337, [revert_polytonicgreek]],
3112 [336, [revert_display_enum]],
3113 [335, [remove_fontsCJK]],
3114 [334, [revert_InsetSpace]],
3115 [333, [revert_paper_sizes]],
3117 [331, [revert_graphics_group]],
3118 [330, [revert_ltcaption]],
3119 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
3120 [328, [revert_master]],
3122 [326, [revert_mexican]],
3123 [325, [revert_pdfpages]],
3125 [323, [revert_linebreaks]],
3126 [322, [revert_pagebreaks]],
3127 [321, [revert_local_layout, revert_plain_layout]],
3128 [320, [revert_tablines]],
3129 [319, [revert_protected_hfill]],
3130 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3131 [317, [remove_extra_embedded_files]],
3132 [316, [revert_wrapplacement]],
3133 [315, [revert_subfig]],
3134 [314, [revert_colsep, revert_plainlayout]],
3136 [312, [revert_module_names]],
3137 [311, [revert_rotfloat, revert_widesideways]],
3138 [310, [revert_external_embedding]],
3139 [309, [revert_btprintall]],
3140 [308, [revert_nocite]],
3141 [307, [revert_serbianlatin]],
3142 [306, [revert_slash, revert_nobreakdash]],
3143 [305, [revert_interlingua]],
3144 [304, [revert_bahasam]],
3145 [303, [revert_framed_notes]],
3147 [301, [revert_latin, revert_samin]],
3148 [300, [revert_linebreak]],
3149 [299, [revert_pagebreak]],
3150 [298, [revert_hyperlinktype]],
3151 [297, [revert_macro_optional_params]],
3152 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3153 [295, [revert_include]],
3154 [294, [revert_href, revert_url]],
3155 [293, [revert_pdf_options_2]],
3156 [292, [revert_inset_info]],
3157 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3158 [290, [revert_vietnamese]],
3159 [289, [revert_wraptable]],
3160 [288, [revert_latexcommand_index]],
3161 [287, [revert_inset_command]],
3162 [286, [revert_wrapfig_options]],
3163 [285, [revert_pdf_options]],
3164 [284, [remove_inzip_options]],
3166 [282, [revert_flex]],
3168 [280, [revert_begin_modules]],
3169 [279, [revert_show_label]],
3170 [278, [revert_long_charstyle_names]],
3176 if __name__ == "__main__":