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 # Convert a LyX length into a LaTeX length
69 units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
70 "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
71 "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
73 # Convert LyX units to LaTeX units
74 for unit in units.keys():
75 if len.find(unit) != -1:
76 len = '%f' % (len2value(len) / 100)
77 len = len.strip('0') + units[unit]
82 # Return the value of len without the unit in numerical form.
84 result = re.search('([+-]?[0-9.]+)', len)
86 return float(result.group(1))
90 # Unfortunately, this doesn't really work, since Standard isn't always default.
91 # But it's as good as we can do right now.
92 def find_default_layout(document, start, end):
93 l = find_token(document.body, "\\begin_layout Standard", start, end)
95 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
97 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
100 def get_option(document, m, option, default):
101 l = document.body[m].find(option)
104 val = document.body[m][l:].split('"')[1]
107 def remove_option(document, m, option):
108 l = document.body[m].find(option)
110 val = document.body[m][l:].split('"')[1]
111 document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
114 def set_option(document, m, option, value):
115 l = document.body[m].find(option)
117 oldval = document.body[m][l:].split('"')[1]
118 l = l + len(option + '="')
119 document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
121 document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
125 def read_unicodesymbols():
126 " Read the unicodesymbols list of unicode characters and corresponding commands."
127 pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
128 fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
130 # Two backslashes, followed by some non-word character, and then a character
131 # in brackets. The idea is to check for constructs like: \"{u}, which is how
132 # they are written in the unicodesymbols file; but they can also be written
134 r = re.compile(r'\\\\(\W)\{(\w)\}')
135 for line in fp.readlines():
136 if line[0] != '#' and line.strip() != "":
137 line=line.replace(' "',' ') # remove all quotation marks with spaces before
138 line=line.replace('" ',' ') # remove all quotation marks with spaces after
139 line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
141 [ucs4,command,dead] = line.split(None,2)
142 if command[0:1] != "\\":
144 spec_chars.append([command, unichr(eval(ucs4))])
150 # If the character is a double-quote, then we need to escape it, too,
151 # since it is done that way in the LyX file.
152 if m.group(1) == "\"":
154 command += m.group(1) + m.group(2)
155 spec_chars.append([command, unichr(eval(ucs4))])
160 def extract_argument(line):
161 'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
166 bracere = re.compile("(\s*)(.*)")
167 n = bracere.match(line)
168 whitespace = n.group(1)
171 if brace != "[" and brace != "{":
195 # We never found the matching brace
196 # So, to be on the safe side, let's just return everything
197 # which will then get wrapped as ERT
199 return (line[:pos + 1], line[pos + 1:])
203 '''Converts LaTeX commands into ERT. line may well be a multi-line
204 string when it is returned.'''
209 ## FIXME Escaped \ ??
210 # This regex looks for a LaTeX command---i.e., something of the form
211 # "\alPhaStuFF", or "\X", where X is any character---where the command
212 # may also be preceded by an additional backslash, which is how it would
213 # appear (e.g.) in an InsetIndex.
214 labelre = re.compile(r'(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)')
216 m = labelre.match(line)
223 (arg, rest) = extract_argument(end)
228 # If we wanted to put labels into an InsetLabel, for example, then we
229 # would just need to test here for cmd == "label" and then take some
230 # appropriate action, i.e., to use arg to get the content and then
231 # wrap it appropriately.
232 cmd = put_cmd_in_ert(cmd)
233 retval += "\n" + cmd + "\n"
235 m = labelre.match(line)
241 '''Takes a string, possibly multi-line, and returns the result of
242 converting LaTeX constructs into LyX constructs. Returns a list of
243 lines, suitable for insertion into document.body.'''
247 # Convert LaTeX to Unicode
248 reps = read_unicodesymbols()
249 # Commands of this sort need to be checked to make sure they are
250 # followed by a non-alpha character, lest we replace too much.
251 hardone = re.compile(r'^\\\\[a-zA-Z]+$')
254 if hardone.match(rep[0]):
257 pos = data.find(rep[0], pos)
260 nextpos = pos + len(rep[0])
261 if nextpos < len(data) and data[nextpos].isalpha():
262 # not the end of that command
265 data = data[:pos] + rep[1] + data[nextpos:]
268 data = data.replace(rep[0], rep[1])
271 data = wrap_into_ert(data, r'\"', '"')
274 mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
275 lines = data.split('\n')
277 #document.warning("LINE: " + line)
278 #document.warning(str(i) + ":" + document.body[i])
279 #document.warning("LAST: " + document.body[-1])
284 f = m.group(2).replace('\\\\', '\\')
289 subst = s.split('\n')
291 retval.append("\\begin_inset Formula " + f)
292 retval.append("\\end_inset")
294 # Handle whatever is left, which is just text
296 subst = g.split('\n')
301 def lyx2latex(lines):
302 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
303 # clean up multiline stuff
306 reps = read_unicodesymbols()
308 for curline in range(len(lines)):
309 line = lines[curline]
310 if line.startswith("\\begin_inset ERT"):
311 # We don't want to replace things inside ERT, so figure out
312 # where the end of the inset is.
313 ert_end = find_end_of_inset(lines, curline + 1)
315 elif line.startswith("\\begin_inset Formula"):
317 elif line.startswith("\\begin_inset Quotes"):
318 # For now, we do a very basic reversion. Someone who understands
319 # quotes is welcome to fix it up.
320 qtype = line[20:].strip()
334 elif line.isspace() or \
335 line.startswith("\\begin_layout") or \
336 line.startswith("\\end_layout") or \
337 line.startswith("\\begin_inset") or \
338 line.startswith("\\end_inset") or \
339 line.startswith("\\lang") or \
340 line.strip() == "status collapsed" or \
341 line.strip() == "status open":
345 # a lossless reversion is not possible
346 # try at least to handle some common insets and settings
347 # do not replace inside ERTs
348 if ert_end >= curline:
349 line = line.replace(r'\backslash', r'\\')
351 # Do the LyX text --> LaTeX conversion
353 line = line.replace(rep[1], rep[0])
354 line = line.replace(r'\backslash', r'\textbackslash{}')
355 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
356 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
357 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
358 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
359 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
360 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
361 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
362 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
363 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
368 ####################################################################
370 def convert_ltcaption(document):
373 i = find_token(document.body, "\\begin_inset Tabular", i)
376 j = find_end_of_inset(document.body, i + 1)
378 document.warning("Malformed LyX document: Could not find end of tabular.")
381 nrows = int(document.body[i+1].split('"')[3])
382 ncols = int(document.body[i+1].split('"')[5])
385 for k in range(nrows):
386 m = find_token(document.body, "<row", m)
389 for k in range(ncols):
390 m = find_token(document.body, "<cell", m)
392 mend = find_token(document.body, "</cell>", m + 1)
393 # first look for caption insets
394 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
395 # then look for ERT captions
397 mcap = find_token(document.body, "caption", m + 1, mend)
399 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
402 if caption == 'true':
404 set_option(document, r, 'caption', 'true')
405 set_option(document, m, 'multicolumn', '1')
406 set_option(document, m, 'bottomline', 'false')
407 set_option(document, m, 'topline', 'false')
408 set_option(document, m, 'rightline', 'false')
409 set_option(document, m, 'leftline', 'false')
410 #j = find_end_of_inset(document.body, j + 1)
412 set_option(document, m, 'multicolumn', '2')
419 #FIXME Use of wrap_into_ert can confuse lyx2lyx
420 def revert_ltcaption(document):
423 i = find_token(document.body, "\\begin_inset Tabular", i)
426 j = find_end_of_inset(document.body, i + 1)
428 document.warning("Malformed LyX document: Could not find end of tabular.")
432 nrows = int(document.body[i+1].split('"')[3])
433 ncols = int(document.body[i+1].split('"')[5])
435 for k in range(nrows):
436 m = find_token(document.body, "<row", m)
437 caption = get_option(document, m, 'caption', 'false')
438 if caption == 'true':
439 remove_option(document, m, 'caption')
440 for k in range(ncols):
441 m = find_token(document.body, "<cell", m)
442 remove_option(document, m, 'multicolumn')
444 m = find_token(document.body, "\\begin_inset Caption", m)
447 m = find_end_of_inset(document.body, m + 1)
448 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
454 def convert_tablines(document):
457 i = find_token(document.body, "\\begin_inset Tabular", i)
459 # LyX 1.3 inserted an extra space between \begin_inset
460 # and Tabular so let us try if this is the case and fix it.
461 i = find_token(document.body, "\\begin_inset Tabular", i)
465 document.body[i] = "\\begin_inset Tabular"
466 j = find_end_of_inset(document.body, i + 1)
468 document.warning("Malformed LyX document: Could not find end of tabular.")
472 nrows = int(document.body[i+1].split('"')[3])
473 ncols = int(document.body[i+1].split('"')[5])
476 for k in range(ncols):
477 m = find_token(document.body, "<column", m)
478 left = get_option(document, m, 'leftline', 'false')
479 right = get_option(document, m, 'rightline', 'false')
480 col_info.append([left, right])
481 remove_option(document, m, 'leftline')
482 remove_option(document, m, 'rightline')
486 for k in range(nrows):
487 m = find_token(document.body, "<row", m)
488 top = get_option(document, m, 'topline', 'false')
489 bottom = get_option(document, m, 'bottomline', 'false')
490 row_info.append([top, bottom])
491 remove_option(document, m, 'topline')
492 remove_option(document, m, 'bottomline')
497 for k in range(nrows*ncols):
498 m = find_token(document.body, "<cell", m)
499 mc_info.append(get_option(document, m, 'multicolumn', '0'))
502 for l in range(nrows):
503 for k in range(ncols):
504 m = find_token(document.body, '<cell', m)
505 if mc_info[l*ncols + k] == '0':
506 r = set_option(document, m, 'topline', row_info[l][0])
507 r = set_option(document, m, 'bottomline', row_info[l][1])
508 r = set_option(document, m, 'leftline', col_info[k][0])
509 r = set_option(document, m, 'rightline', col_info[k][1])
510 elif mc_info[l*ncols + k] == '1':
512 while s < ncols and mc_info[l*ncols + s] == '2':
514 if s < ncols and mc_info[l*ncols + s] != '1':
515 r = set_option(document, m, 'rightline', col_info[k][1])
516 if k > 0 and mc_info[l*ncols + k - 1] == '0':
517 r = set_option(document, m, 'leftline', col_info[k][0])
522 def revert_tablines(document):
525 i = find_token(document.body, "\\begin_inset Tabular", i)
528 j = find_end_of_inset(document.body, i + 1)
530 document.warning("Malformed LyX document: Could not find end of tabular.")
534 nrows = int(document.body[i+1].split('"')[3])
535 ncols = int(document.body[i+1].split('"')[5])
538 for k in range(nrows*ncols):
539 m = find_token(document.body, "<cell", m)
540 top = get_option(document, m, 'topline', 'false')
541 bottom = get_option(document, m, 'bottomline', 'false')
542 left = get_option(document, m, 'leftline', 'false')
543 right = get_option(document, m, 'rightline', 'false')
544 lines.append([top, bottom, left, right])
547 # we will want to ignore longtable captions
550 for k in range(nrows):
551 m = find_token(document.body, "<row", m)
552 caption = get_option(document, m, 'caption', 'false')
553 caption_info.append([caption])
558 for k in range(ncols):
559 m = find_token(document.body, "<column", m)
561 for l in range(nrows):
562 left = lines[l*ncols + k][2]
563 if left == 'false' and caption_info[l] == 'false':
565 set_option(document, m, 'leftline', left)
567 for l in range(nrows):
568 right = lines[l*ncols + k][3]
569 if right == 'false' and caption_info[l] == 'false':
571 set_option(document, m, 'rightline', right)
575 for k in range(nrows):
576 m = find_token(document.body, "<row", m)
578 for l in range(ncols):
579 top = lines[k*ncols + l][0]
582 if caption_info[k] == 'false':
584 set_option(document, m, 'topline', top)
586 for l in range(ncols):
587 bottom = lines[k*ncols + l][1]
588 if bottom == 'false':
590 if caption_info[k] == 'false':
592 set_option(document, m, 'bottomline', bottom)
598 def fix_wrong_tables(document):
601 i = find_token(document.body, "\\begin_inset Tabular", i)
604 j = find_end_of_inset(document.body, i + 1)
606 document.warning("Malformed LyX document: Could not find end of tabular.")
610 nrows = int(document.body[i+1].split('"')[3])
611 ncols = int(document.body[i+1].split('"')[5])
613 for l in range(nrows):
615 for k in range(ncols):
616 m = find_token(document.body, '<cell', m)
618 if document.body[m].find('multicolumn') != -1:
619 multicol_cont = int(document.body[m].split('"')[1])
621 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
622 document.body[m] = document.body[m][:5] + document.body[m][21:]
625 prev_multicolumn = multicol_cont
632 def close_begin_deeper(document):
636 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
641 if document.body[i][:13] == "\\begin_deeper":
648 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
651 def long_charstyle_names(document):
654 i = find_token(document.body, "\\begin_inset CharStyle", i)
657 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
660 def revert_long_charstyle_names(document):
663 i = find_token(document.body, "\\begin_inset CharStyle", i)
666 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
670 def axe_show_label(document):
673 i = find_token(document.body, "\\begin_inset CharStyle", i)
676 if document.body[i + 1].find("show_label") != -1:
677 if document.body[i + 1].find("true") != -1:
678 document.body[i + 1] = "status open"
679 del document.body[ i + 2]
681 if document.body[i + 1].find("false") != -1:
682 document.body[i + 1] = "status collapsed"
683 del document.body[ i + 2]
685 document.warning("Malformed LyX document: show_label neither false nor true.")
687 document.warning("Malformed LyX document: show_label missing in CharStyle.")
692 def revert_show_label(document):
695 i = find_token(document.body, "\\begin_inset CharStyle", i)
698 if document.body[i + 1].find("status open") != -1:
699 document.body.insert(i + 1, "show_label true")
701 if document.body[i + 1].find("status collapsed") != -1:
702 document.body.insert(i + 1, "show_label false")
704 document.warning("Malformed LyX document: no legal status line in CharStyle.")
707 def revert_begin_modules(document):
710 i = find_token(document.header, "\\begin_modules", i)
713 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
715 # this should not happen
717 document.header[i : j + 1] = []
719 def convert_flex(document):
720 "Convert CharStyle to Flex"
723 i = find_token(document.body, "\\begin_inset CharStyle", i)
726 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
728 def revert_flex(document):
729 "Convert Flex to CharStyle"
732 i = find_token(document.body, "\\begin_inset Flex", i)
735 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
738 # Discard PDF options for hyperref
739 def revert_pdf_options(document):
740 "Revert PDF options for hyperref."
741 # store the PDF options and delete the entries from the Lyx file
749 bookmarksnumbered = ""
751 bookmarksopenlevel = ""
759 i = find_token(document.header, "\\use_hyperref", i)
761 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
762 del document.header[i]
763 i = find_token(document.header, "\\pdf_store_options", i)
765 del document.header[i]
766 i = find_token(document.header, "\\pdf_title", 0)
768 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
769 title = ' pdftitle={' + title + '}'
770 del document.header[i]
771 i = find_token(document.header, "\\pdf_author", 0)
773 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
775 author = ' pdfauthor={' + author + '}'
777 author = ',\n pdfauthor={' + author + '}'
778 del document.header[i]
779 i = find_token(document.header, "\\pdf_subject", 0)
781 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
782 if title == "" and author == "":
783 subject = ' pdfsubject={' + subject + '}'
785 subject = ',\n pdfsubject={' + subject + '}'
786 del document.header[i]
787 i = find_token(document.header, "\\pdf_keywords", 0)
789 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
790 if title == "" and author == "" and subject == "":
791 keywords = ' pdfkeywords={' + keywords + '}'
793 keywords = ',\n pdfkeywords={' + keywords + '}'
794 del document.header[i]
795 i = find_token(document.header, "\\pdf_bookmarks", 0)
797 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
798 bookmarks = ',\n bookmarks=' + bookmarks
799 del document.header[i]
800 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
802 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
803 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
804 del document.header[i]
805 i = find_token(document.header, "\\pdf_bookmarksopen", i)
807 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
808 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
809 del document.header[i]
810 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
812 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
813 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
814 del document.header[i]
815 i = find_token(document.header, "\\pdf_breaklinks", i)
817 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
818 breaklinks = ',\n breaklinks=' + breaklinks
819 del document.header[i]
820 i = find_token(document.header, "\\pdf_pdfborder", i)
822 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
823 if pdfborder == 'true':
824 pdfborder = ',\n pdfborder={0 0 0}'
826 pdfborder = ',\n pdfborder={0 0 1}'
827 del document.header[i]
828 i = find_token(document.header, "\\pdf_colorlinks", i)
830 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
831 colorlinks = ',\n colorlinks=' + colorlinks
832 del document.header[i]
833 i = find_token(document.header, "\\pdf_backref", i)
835 backref = get_value_string(document.header, '\\pdf_backref', 0)
836 backref = ',\n backref=' + backref
837 del document.header[i]
838 i = find_token(document.header, "\\pdf_pagebackref", i)
840 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
841 pagebackref = ',\n pagebackref=' + pagebackref
842 del document.header[i]
843 i = find_token(document.header, "\\pdf_pagemode", 0)
845 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
846 pagemode = ',\n pdfpagemode=' + pagemode
847 del document.header[i]
848 i = find_token(document.header, "\\pdf_quoted_options", 0)
850 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
851 if title == "" and author == "" and subject == "" and keywords == "":
852 otheroptions = ' ' + otheroptions
854 otheroptions = ',\n ' + otheroptions
855 del document.header[i]
857 # write to the preamble when hyperref was used
859 # preamble write preparations
860 # bookmark numbers are only output when they are turned on
861 if bookmarksopen == ',\n bookmarksopen=true':
862 bookmarksopen = bookmarksopen + bookmarksopenlevel
863 if bookmarks == ',\n bookmarks=true':
864 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
866 bookmarks = bookmarks
867 # hypersetup is only output when there are things to be set up
868 setupstart = '\\hypersetup{%\n'
870 if otheroptions == "" and title == "" and author == ""\
871 and subject == "" and keywords == "":
875 add_to_preamble(document,
876 ['% Commands inserted by lyx2lyx for PDF properties',
877 '\\usepackage[unicode=true'
896 def remove_inzip_options(document):
897 "Remove inzipName and embed options from the Graphics inset"
900 i = find_token(document.body, "\\begin_inset Graphics", i)
903 j = find_end_of_inset(document.body, i + 1)
906 document.warning("Malformed LyX document: Could not find end of graphics inset.")
907 # If there's a inzip param, just remove that
908 k = find_token(document.body, "\tinzipName", i + 1, j)
911 # embed option must follow the inzipName option
912 del document.body[k+1]
916 def convert_inset_command(document):
919 \begin_inset LatexCommand cmd
921 \begin_inset CommandInset InsetType
926 i = find_token(document.body, "\\begin_inset LatexCommand", i)
929 line = document.body[i]
930 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
934 #this is adapted from factory.cpp
935 if cmdName[0:4].lower() == "cite":
936 insetName = "citation"
937 elif cmdName == "url" or cmdName == "htmlurl":
939 elif cmdName[-3:] == "ref":
941 elif cmdName == "tableofcontents":
943 elif cmdName == "printnomenclature":
944 insetName = "nomencl_print"
945 elif cmdName == "printindex":
946 insetName = "index_print"
949 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
950 document.body[i : i+1] = insertion
953 def revert_inset_command(document):
956 \begin_inset CommandInset InsetType
959 \begin_inset LatexCommand cmd
960 Some insets may end up being converted to insets earlier versions of LyX
961 will not be able to recognize. Not sure what to do about that.
965 i = find_token(document.body, "\\begin_inset CommandInset", i)
968 nextline = document.body[i+1]
969 r = re.compile(r'LatexCommand\s+(.*)$')
970 m = r.match(nextline)
972 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
975 insertion = ["\\begin_inset LatexCommand " + cmdName]
976 document.body[i : i+2] = insertion
979 def convert_wrapfig_options(document):
980 "Convert optional options for wrap floats (wrapfig)."
981 # adds the tokens "lines", "placement", and "overhang"
984 i = find_token(document.body, "\\begin_inset Wrap figure", i)
987 document.body.insert(i + 1, "lines 0")
988 j = find_token(document.body, "placement", i)
989 # placement can be already set or not; if not, set it
991 document.body.insert(i + 3, "overhang 0col%")
993 document.body.insert(i + 2, "placement o")
994 document.body.insert(i + 3, "overhang 0col%")
998 def revert_wrapfig_options(document):
999 "Revert optional options for wrap floats (wrapfig)."
1002 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1005 j = find_end_of_inset(document.body, i)
1007 document.warning("Can't find end of Wrap inset at line " + str(i))
1010 k = find_default_layout(document, i, j)
1012 document.warning("Can't find default layout for Wrap figure!")
1015 # Options should be between i and k now
1016 l = find_token(document.body, "lines", i, k)
1018 document.warning("Can't find lines option for Wrap figure!")
1021 m = find_token(document.body, "overhang", i + 1, k)
1023 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1026 # Do these in reverse order
1027 del document.body[m]
1028 del document.body[l]
1032 def convert_latexcommand_index(document):
1033 "Convert from LatexCommand form to collapsable form."
1035 r1 = re.compile('name "(.*)"')
1037 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1040 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1042 j = find_end_of_inset(document.body, i + 2)
1044 document.warning("Unable to find end of index inset at line " + i + "!")
1047 m = r1.match(document.body[i + 2])
1049 document.warning("Unable to match: " + document.body[i+2])
1052 fullcontent = m.group(1)
1053 linelist = latex2lyx(fullcontent)
1054 #document.warning(fullcontent)
1056 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1057 linelist + ["\\end_layout"]
1058 document.body[i : j] = linelist
1059 i += len(linelist) - (j - i)
1062 def revert_latexcommand_index(document):
1063 "Revert from collapsable form to LatexCommand form."
1066 i = find_token(document.body, "\\begin_inset Index", i)
1069 j = find_end_of_inset(document.body, i + 1)
1073 content = lyx2latex(document.body[i:j])
1075 content = content.replace('"', r'\"')
1076 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1077 "name " + '"' + content + '"', ""]
1081 def revert_wraptable(document):
1082 "Revert wrap table to wrap figure."
1085 i = find_token(document.body, "\\begin_inset Wrap table", i)
1088 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1092 def revert_vietnamese(document):
1093 "Set language Vietnamese to English"
1094 # Set document language from Vietnamese to English
1096 if document.language == "vietnamese":
1097 document.language = "english"
1098 i = find_token(document.header, "\\language", 0)
1100 document.header[i] = "\\language english"
1103 j = find_token(document.body, "\\lang vietnamese", j)
1106 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1110 def convert_japanese_cjk(document):
1111 "Set language japanese to japanese-cjk"
1112 # Set document language from japanese-plain to japanese
1114 if document.language == "japanese":
1115 document.language = "japanese-cjk"
1116 i = find_token(document.header, "\\language", 0)
1118 document.header[i] = "\\language japanese-cjk"
1121 j = find_token(document.body, "\\lang japanese", j)
1124 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1128 def revert_japanese(document):
1129 "Set language japanese-plain to japanese"
1130 # Set document language from japanese-plain to japanese
1132 if document.language == "japanese-plain":
1133 document.language = "japanese"
1134 i = find_token(document.header, "\\language", 0)
1136 document.header[i] = "\\language japanese"
1139 j = find_token(document.body, "\\lang japanese-plain", j)
1142 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1146 def revert_japanese_cjk(document):
1147 "Set language japanese-cjk to japanese"
1148 # Set document language from japanese-plain to japanese
1150 if document.language == "japanese-cjk":
1151 document.language = "japanese"
1152 i = find_token(document.header, "\\language", 0)
1154 document.header[i] = "\\language japanese"
1157 j = find_token(document.body, "\\lang japanese-cjk", j)
1160 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1164 def revert_japanese_encoding(document):
1165 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1166 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1168 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1170 document.header[i] = "\\inputencoding EUC-JP"
1172 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1174 document.header[j] = "\\inputencoding JIS"
1176 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1177 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1178 document.header[k] = "\\inputencoding UTF8"
1181 def revert_inset_info(document):
1182 'Replace info inset with its content'
1185 i = find_token(document.body, '\\begin_inset Info', i)
1188 j = find_end_of_inset(document.body, i + 1)
1191 document.warning("Malformed LyX document: Could not find end of Info inset.")
1194 for k in range(i, j+1):
1195 if document.body[k].startswith("arg"):
1196 arg = document.body[k][3:].strip().strip('"')
1197 if document.body[k].startswith("type"):
1198 type = document.body[k][4:].strip().strip('"')
1199 # I think there is a newline after \\end_inset, which should be removed.
1200 if document.body[j + 1].strip() == "":
1201 document.body[i : (j + 2)] = [type + ':' + arg]
1203 document.body[i : (j + 1)] = [type + ':' + arg]
1206 def convert_pdf_options(document):
1207 # Set the pdfusetitle tag, delete the pdf_store_options,
1208 # set quotes for bookmarksopenlevel"
1209 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1211 k = find_token(document.header, "\\use_hyperref", 0)
1212 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1213 k = find_token(document.header, "\\pdf_store_options", 0)
1215 del document.header[k]
1216 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1218 document.header[i] = document.header[i].replace('"', '')
1221 def revert_pdf_options_2(document):
1222 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1223 k = find_token(document.header, "\\use_hyperref", 0)
1224 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1226 del document.header[i]
1227 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1229 values = document.header[i].split()
1230 values[1] = ' "' + values[1] + '"'
1231 document.header[i] = ''.join(values)
1234 def convert_htmlurl(document):
1235 'Convert "htmlurl" to "href" insets for docbook'
1236 if document.backend != "docbook":
1240 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1243 document.body[i] = "\\begin_inset CommandInset href"
1244 document.body[i + 1] = "LatexCommand href"
1248 def convert_url(document):
1249 'Convert url insets to url charstyles'
1250 if document.backend == "docbook":
1254 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1257 n = find_token(document.body, "name", i)
1259 # place the URL name in typewriter before the new URL insert
1260 # grab the name 'bla' from the e.g. the line 'name "bla"',
1261 # therefore start with the 6th character
1262 name = document.body[n][6:-1]
1263 newname = [name + " "]
1264 document.body[i:i] = newname
1266 j = find_token(document.body, "target", i)
1268 document.warning("Malformed LyX document: Can't find target for url inset")
1271 target = document.body[j][8:-1]
1272 k = find_token(document.body, "\\end_inset", j)
1274 document.warning("Malformed LyX document: Can't find end of url inset")
1277 newstuff = ["\\begin_inset Flex URL",
1278 "status collapsed", "",
1279 "\\begin_layout Standard",
1284 document.body[i:k] = newstuff
1287 def convert_ams_classes(document):
1288 tc = document.textclass
1289 if (tc != "amsart" and tc != "amsart-plain" and
1290 tc != "amsart-seq" and tc != "amsbook"):
1292 if tc == "amsart-plain":
1293 document.textclass = "amsart"
1294 document.set_textclass()
1295 document.add_module("Theorems (Starred)")
1297 if tc == "amsart-seq":
1298 document.textclass = "amsart"
1299 document.set_textclass()
1300 document.add_module("Theorems (AMS)")
1302 #Now we want to see if any of the environments in the extended theorems
1303 #module were used in this document. If so, we'll add that module, too.
1304 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1305 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1308 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1311 i = find_token(document.body, "\\begin_layout", i)
1314 m = r.match(document.body[i])
1316 # This is an empty layout
1317 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1321 if layouts.count(m) != 0:
1322 document.add_module("Theorems (AMS-Extended)")
1326 def revert_href(document):
1327 'Reverts hyperlink insets (href) to url insets (url)'
1330 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1333 document.body[i : i + 2] = \
1334 ["\\begin_inset CommandInset url", "LatexCommand url"]
1337 def revert_url(document):
1338 'Reverts Flex URL insets to old-style URL insets'
1341 i = find_token(document.body, "\\begin_inset Flex URL", i)
1344 j = find_end_of_inset(document.body, i)
1346 document.warning("Can't find end of inset in revert_url!")
1348 k = find_default_layout(document, i, j)
1350 document.warning("Can't find default layout in revert_url!")
1353 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1354 if l == -1 or l >= j:
1355 document.warning("Can't find end of default layout in revert_url!")
1358 # OK, so the inset's data is between lines k and l.
1359 data = " ".join(document.body[k+1:l])
1361 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1363 document.body[i:j+1] = newinset
1364 i = i + len(newinset)
1367 def convert_include(document):
1368 'Converts include insets to new format.'
1370 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1372 i = find_token(document.body, "\\begin_inset Include", i)
1375 line = document.body[i]
1376 previewline = document.body[i + 1]
1379 document.warning("Unable to match line " + str(i) + " of body!")
1385 insertion = ["\\begin_inset CommandInset include",
1386 "LatexCommand " + cmd, previewline,
1387 "filename \"" + fn + "\""]
1390 insertion.append("lstparams " + '"' + opt + '"')
1392 document.body[i : i + 2] = insertion
1396 def revert_include(document):
1397 'Reverts include insets to old format.'
1399 r0 = re.compile('preview.*')
1400 r1 = re.compile('LatexCommand (.+)')
1401 r2 = re.compile('filename "(.+)"')
1402 r3 = re.compile('lstparams "(.*)"')
1404 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1408 if r0.match(document.body[nextline]):
1409 previewline = document.body[nextline]
1413 m = r1.match(document.body[nextline])
1415 document.warning("Malformed LyX document: No LatexCommand line for `" +
1416 document.body[i] + "' on line " + str(i) + ".")
1421 m = r2.match(document.body[nextline])
1423 document.warning("Malformed LyX document: No filename line for `" + \
1424 document.body[i] + "' on line " + str(i) + ".")
1430 if (cmd == "lstinputlisting"):
1431 m = r3.match(document.body[nextline])
1433 options = m.group(1)
1436 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1438 newline += ("[" + options + "]")
1439 insertion = [newline]
1440 if previewline != "":
1441 insertion.append(previewline)
1442 document.body[i : nextline] = insertion
1446 def revert_albanian(document):
1447 "Set language Albanian to English"
1449 if document.language == "albanian":
1450 document.language = "english"
1451 i = find_token(document.header, "\\language", 0)
1453 document.header[i] = "\\language english"
1456 j = find_token(document.body, "\\lang albanian", j)
1459 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1463 def revert_lowersorbian(document):
1464 "Set language lower Sorbian to English"
1466 if document.language == "lowersorbian":
1467 document.language = "english"
1468 i = find_token(document.header, "\\language", 0)
1470 document.header[i] = "\\language english"
1473 j = find_token(document.body, "\\lang lowersorbian", j)
1476 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1480 def revert_uppersorbian(document):
1481 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1483 if document.language == "uppersorbian":
1484 document.language = "usorbian"
1485 i = find_token(document.header, "\\language", 0)
1487 document.header[i] = "\\language usorbian"
1490 j = find_token(document.body, "\\lang uppersorbian", j)
1493 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1497 def convert_usorbian(document):
1498 "Set language usorbian to uppersorbian"
1500 if document.language == "usorbian":
1501 document.language = "uppersorbian"
1502 i = find_token(document.header, "\\language", 0)
1504 document.header[i] = "\\language uppersorbian"
1507 j = find_token(document.body, "\\lang usorbian", j)
1510 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1514 def revert_macro_optional_params(document):
1515 "Convert macro definitions with optional parameters into ERTs"
1516 # Stub to convert macro definitions with one or more optional parameters
1517 # into uninterpreted ERT insets
1520 def revert_hyperlinktype(document):
1521 'Reverts hyperlink type'
1525 i = find_token(document.body, "target", i)
1528 j = find_token(document.body, "type", i)
1532 del document.body[j]
1536 def revert_pagebreak(document):
1537 'Reverts pagebreak to ERT'
1540 i = find_token(document.body, "\\pagebreak", i)
1543 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1544 '\\begin_layout Standard\n\n\n\\backslash\n' \
1545 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1549 def revert_linebreak(document):
1550 'Reverts linebreak to ERT'
1553 i = find_token(document.body, "\\linebreak", i)
1556 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1557 '\\begin_layout Standard\n\n\n\\backslash\n' \
1558 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1562 def revert_latin(document):
1563 "Set language Latin to English"
1565 if document.language == "latin":
1566 document.language = "english"
1567 i = find_token(document.header, "\\language", 0)
1569 document.header[i] = "\\language english"
1572 j = find_token(document.body, "\\lang latin", j)
1575 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1579 def revert_samin(document):
1580 "Set language North Sami to English"
1582 if document.language == "samin":
1583 document.language = "english"
1584 i = find_token(document.header, "\\language", 0)
1586 document.header[i] = "\\language english"
1589 j = find_token(document.body, "\\lang samin", j)
1592 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1596 def convert_serbocroatian(document):
1597 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1599 if document.language == "serbocroatian":
1600 document.language = "croatian"
1601 i = find_token(document.header, "\\language", 0)
1603 document.header[i] = "\\language croatian"
1606 j = find_token(document.body, "\\lang serbocroatian", j)
1609 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1613 def convert_framed_notes(document):
1614 "Convert framed notes to boxes. "
1617 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1620 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1629 'height_special "totalheight"']
1630 document.body[i:i+1] = subst
1634 def convert_module_names(document):
1635 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1636 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1637 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1638 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1639 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1640 modlist = document.get_module_list()
1641 if len(modlist) == 0:
1645 if modulemap.has_key(mod):
1646 newmodlist.append(modulemap[mod])
1648 document.warning("Can't find module %s in the module map!" % mod)
1649 newmodlist.append(mod)
1650 document.set_module_list(newmodlist)
1653 def revert_module_names(document):
1654 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1655 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1656 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1657 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1658 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1659 modlist = document.get_module_list()
1660 if len(modlist) == 0:
1664 if modulemap.has_key(mod):
1665 newmodlist.append(modulemap[mod])
1667 document.warning("Can't find module %s in the module map!" % mod)
1668 newmodlist.append(mod)
1669 document.set_module_list(newmodlist)
1672 def revert_colsep(document):
1673 i = find_token(document.header, "\\columnsep", 0)
1676 colsepline = document.header[i]
1677 r = re.compile(r'\\columnsep (.*)')
1678 m = r.match(colsepline)
1680 document.warning("Malformed column separation line!")
1683 del document.header[i]
1684 #it seems to be safe to add the package even if it is already used
1685 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1687 add_to_preamble(document, pretext)
1690 def revert_framed_notes(document):
1691 "Revert framed boxes to notes. "
1694 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1698 j = find_end_of_inset(document.body, i + 1)
1701 document.warning("Malformed LyX document: Could not find end of Box inset.")
1702 k = find_token(document.body, "status", i + 1, j)
1704 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1706 status = document.body[k]
1707 l = find_default_layout(document, i + 1, j)
1709 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1711 m = find_token(document.body, "\\end_layout", i + 1, j)
1713 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1715 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1716 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1717 if ibox == -1 and pbox == -1:
1718 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1719 del document.body[i+1:k]
1721 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1722 subst1 = [document.body[l],
1723 "\\begin_inset Note Shaded",
1725 '\\begin_layout Standard']
1726 document.body[l:l + 1] = subst1
1727 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1728 document.body[m:m + 1] = subst2
1732 def revert_slash(document):
1733 'Revert \\SpecialChar \\slash{} to ERT'
1734 r = re.compile(r'\\SpecialChar \\slash{}')
1736 while i < len(document.body):
1737 m = r.match(document.body[i])
1739 subst = ['\\begin_inset ERT',
1740 'status collapsed', '',
1741 '\\begin_layout Standard',
1742 '', '', '\\backslash',
1746 document.body[i: i+1] = subst
1752 def revert_nobreakdash(document):
1753 'Revert \\SpecialChar \\nobreakdash- to ERT'
1755 while i < len(document.body):
1756 line = document.body[i]
1757 r = re.compile(r'\\SpecialChar \\nobreakdash-')
1760 subst = ['\\begin_inset ERT',
1761 'status collapsed', '',
1762 '\\begin_layout Standard', '', '',
1767 document.body[i:i+1] = subst
1769 j = find_token(document.header, "\\use_amsmath", 0)
1771 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1773 document.header[j] = "\\use_amsmath 2"
1778 #Returns number of lines added/removed
1779 def revert_nocite_key(body, start, end):
1780 'key "..." -> \nocite{...}'
1781 r = re.compile(r'^key "(.*)"')
1785 m = r.match(body[i])
1787 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1788 j += 1 # because we added a line
1789 i += 2 # skip that line
1792 j -= 1 # because we deleted a line
1793 # no need to change i, since it now points to the next line
1797 def revert_nocite(document):
1798 "Revert LatexCommand nocite to ERT"
1801 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1804 if (document.body[i+1] != "LatexCommand nocite"):
1805 # note that we already incremented i
1808 insetEnd = find_end_of_inset(document.body, i)
1810 #this should not happen
1811 document.warning("End of CommandInset citation not found in revert_nocite!")
1814 paramLocation = i + 2 #start of the inset's parameters
1816 document.body[i:i+2] = \
1817 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1818 # that added two lines
1821 #print insetEnd, document.body[i: insetEnd + 1]
1822 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1823 #print insetEnd, document.body[i: insetEnd + 1]
1824 document.body.insert(insetEnd, "\\end_layout")
1825 document.body.insert(insetEnd + 1, "")
1829 def revert_btprintall(document):
1830 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1831 i = find_token(document.header, '\\use_bibtopic', 0)
1833 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1835 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1837 while i < len(document.body):
1838 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1841 j = find_end_of_inset(document.body, i + 1)
1843 #this should not happen
1844 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1845 j = len(document.body)
1846 # this range isn't really right, but it should be OK, since we shouldn't
1847 # see more than one matching line in each inset
1849 for k in range(i, j):
1850 if (document.body[k] == 'btprint "btPrintAll"'):
1851 del document.body[k]
1852 subst = ["\\begin_inset ERT",
1853 "status collapsed", "",
1854 "\\begin_layout Standard", "",
1859 document.body[i:i] = subst
1860 addlines = addedlines + len(subst) - 1
1864 def revert_bahasam(document):
1865 "Set language Bahasa Malaysia to Bahasa Indonesia"
1867 if document.language == "bahasam":
1868 document.language = "bahasa"
1869 i = find_token(document.header, "\\language", 0)
1871 document.header[i] = "\\language bahasa"
1874 j = find_token(document.body, "\\lang bahasam", j)
1877 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1881 def revert_interlingua(document):
1882 "Set language Interlingua to English"
1884 if document.language == "interlingua":
1885 document.language = "english"
1886 i = find_token(document.header, "\\language", 0)
1888 document.header[i] = "\\language english"
1891 j = find_token(document.body, "\\lang interlingua", j)
1894 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1898 def revert_serbianlatin(document):
1899 "Set language Serbian-Latin to Croatian"
1901 if document.language == "serbian-latin":
1902 document.language = "croatian"
1903 i = find_token(document.header, "\\language", 0)
1905 document.header[i] = "\\language croatian"
1908 j = find_token(document.body, "\\lang serbian-latin", j)
1911 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
1915 def revert_rotfloat(document):
1916 " Revert sideways custom floats. "
1919 # whitespace intended (exclude \\begin_inset FloatList)
1920 i = find_token(document.body, "\\begin_inset Float ", i)
1923 line = document.body[i]
1924 r = re.compile(r'\\begin_inset Float (.*)$')
1927 document.warning("Unable to match line " + str(i) + " of body!")
1930 floattype = m.group(1)
1931 if floattype == "figure" or floattype == "table":
1934 j = find_end_of_inset(document.body, i)
1936 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
1940 if get_value(document.body, 'sideways', i, j) == "false":
1943 l = find_default_layout(document, i + 1, j)
1945 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1947 subst = ['\\begin_layout Standard',
1948 '\\begin_inset ERT',
1949 'status collapsed', '',
1950 '\\begin_layout Standard', '', '',
1952 'end{sideways' + floattype + '}',
1953 '\\end_layout', '', '\\end_inset']
1954 document.body[j : j+1] = subst
1955 addedLines = len(subst) - 1
1956 del document.body[i+1 : l]
1957 addedLines -= (l-1) - (i+1)
1958 subst = ['\\begin_inset ERT', 'status collapsed', '',
1959 '\\begin_layout Standard', '', '', '\\backslash',
1960 'begin{sideways' + floattype + '}',
1961 '\\end_layout', '', '\\end_inset', '',
1963 document.body[i : i+1] = subst
1964 addedLines += len(subst) - 1
1965 if floattype == "algorithm":
1966 add_to_preamble(document,
1967 ['% Commands inserted by lyx2lyx for sideways algorithm float',
1968 '\\usepackage{rotfloat}',
1969 '\\floatstyle{ruled}',
1970 '\\newfloat{algorithm}{tbp}{loa}',
1971 '\\floatname{algorithm}{Algorithm}'])
1973 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
1977 def revert_widesideways(document):
1978 " Revert wide sideways floats. "
1981 # whitespace intended (exclude \\begin_inset FloatList)
1982 i = find_token(document.body, '\\begin_inset Float ', i)
1985 line = document.body[i]
1986 r = re.compile(r'\\begin_inset Float (.*)$')
1989 document.warning("Unable to match line " + str(i) + " of body!")
1992 floattype = m.group(1)
1993 if floattype != "figure" and floattype != "table":
1996 j = find_end_of_inset(document.body, i)
1998 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2001 if get_value(document.body, 'sideways', i, j) == "false" or \
2002 get_value(document.body, 'wide', i, j) == "false":
2005 l = find_default_layout(document, i + 1, j)
2007 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2009 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2010 'status collapsed', '',
2011 '\\begin_layout Standard', '', '', '\\backslash',
2012 'end{sideways' + floattype + '*}',
2013 '\\end_layout', '', '\\end_inset']
2014 document.body[j : j+1] = subst
2015 addedLines = len(subst) - 1
2016 del document.body[i+1:l-1]
2017 addedLines -= (l-1) - (i+1)
2018 subst = ['\\begin_inset ERT', 'status collapsed', '',
2019 '\\begin_layout Standard', '', '', '\\backslash',
2020 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2021 '\\end_inset', '', '\\end_layout', '']
2022 document.body[i : i+1] = subst
2023 addedLines += len(subst) - 1
2024 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2028 def revert_inset_embedding(document, type):
2029 ' Remove embed tag from certain type of insets'
2032 i = find_token(document.body, "\\begin_inset %s" % type, i)
2035 j = find_end_of_inset(document.body, i)
2037 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2040 k = find_token(document.body, "\tembed", i, j)
2042 k = find_token(document.body, "embed", i, j)
2044 del document.body[k]
2048 def revert_external_embedding(document):
2049 ' Remove embed tag from external inset '
2050 revert_inset_embedding(document, 'External')
2053 def convert_subfig(document):
2054 " Convert subfigures to subfloats. "
2057 i = find_token(document.body, '\\begin_inset Graphics', i)
2060 endInset = find_end_of_inset(document.body, i)
2062 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2065 k = find_token(document.body, '\tsubcaption', i, endInset)
2069 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2071 document.warning("Malformed lyx document: Can't find subcaptionText!")
2074 caption = document.body[l][16:].strip('"')
2075 del document.body[l]
2076 del document.body[k]
2078 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2079 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2080 '', '\\begin_layout Plain Layout'] + latex2lyx(caption) + \
2081 [ '\\end_layout', '', '\\end_inset', '',
2082 '\\end_layout', '', '\\begin_layout Plain Layout']
2083 document.body[i : i] = subst
2084 addedLines += len(subst)
2085 endInset += addedLines
2086 subst = ['', '\\end_inset', '', '\\end_layout']
2087 document.body[endInset : endInset] = subst
2088 addedLines += len(subst)
2092 def revert_subfig(document):
2093 " Revert subfloats. "
2096 # whitespace intended (exclude \\begin_inset FloatList)
2097 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2103 j = find_end_of_inset(document.body, i)
2105 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2106 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2108 continue # this will get us back to the outer loop, since j == -1
2109 # look for embedded float (= subfloat)
2110 # whitespace intended (exclude \\begin_inset FloatList)
2111 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2114 l = find_end_of_inset(document.body, k)
2116 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2119 continue # escape to the outer loop
2120 m = find_default_layout(document, k + 1, l)
2122 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2127 capend = find_end_of_inset(document.body, cap)
2129 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2133 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2135 lblend = find_end_of_inset(document.body, lbl + 1)
2137 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2139 for line in document.body[lbl:lblend + 1]:
2140 if line.startswith('name '):
2141 label = line.split()[1].strip('"')
2148 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2150 optend = find_end_of_inset(document.body, opt)
2152 document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
2154 optc = find_default_layout(document, opt, optend)
2156 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2158 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2159 for line in document.body[optc:optcend]:
2160 if not line.startswith('\\'):
2161 shortcap += line.strip()
2165 for line in document.body[cap:capend]:
2166 if line in document.body[lbl:lblend]:
2168 elif line in document.body[opt:optend]:
2170 elif not line.startswith('\\'):
2171 caption += line.strip()
2173 caption += "\\backslash\nlabel{" + label + "}"
2174 subst = '\\begin_layout Plain Layout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2175 '\\begin_layout Plain Layout\n\n}\n\\end_layout\n\n\\end_inset\n\n' \
2176 '\\end_layout\n\n\\begin_layout Plain Layout\n'
2177 subst = subst.split('\n')
2178 document.body[l : l+1] = subst
2179 addedLines = len(subst) - 1
2180 # this is before l and so is unchanged by the multiline insertion
2182 del document.body[cap:capend+1]
2183 addedLines -= (capend + 1 - cap)
2184 del document.body[k+1:m-1]
2185 addedLines -= (m - 1 - (k + 1))
2186 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2187 '\\begin_layout Plain Layout\n\n\\backslash\n' \
2189 if len(shortcap) > 0:
2190 insertion = insertion + "[" + shortcap + "]"
2191 if len(caption) > 0:
2192 insertion = insertion + "[" + caption + "]"
2193 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2194 insertion = insertion.split('\n')
2195 document.body[k : k + 1] = insertion
2196 addedLines += len(insertion) - 1
2197 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2201 def revert_wrapplacement(document):
2202 " Revert placement options wrap floats (wrapfig). "
2205 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2208 e = find_end_of_inset(document.body, i)
2209 j = find_token(document.body, "placement", i + 1, e)
2211 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2214 r = re.compile("placement (o|i|l|r)")
2215 m = r.match(document.body[j])
2217 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2218 document.body[j] = "placement " + m.group(1).lower()
2222 def remove_extra_embedded_files(document):
2223 " Remove \extra_embedded_files from buffer params "
2224 i = find_token(document.header, '\\extra_embedded_files', 0)
2227 document.header.pop(i)
2230 def convert_spaceinset(document):
2231 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2233 while i < len(document.body):
2234 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2238 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2239 document.body[i: i+1] = subst
2245 def revert_spaceinset(document):
2246 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2249 i = find_token(document.body, "\\begin_inset Space", i)
2252 j = find_end_of_inset(document.body, i)
2254 document.warning("Malformed LyX document: Could not find end of space inset.")
2256 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2257 del document.body[j]
2260 def convert_hfill(document):
2261 " Convert hfill to space inset "
2264 i = find_token(document.body, "\\hfill", i)
2267 subst = document.body[i].replace('\\hfill', \
2268 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2269 subst = subst.split('\n')
2270 document.body[i : i+1] = subst
2274 def revert_hfills(document):
2275 ' Revert \\hfill commands '
2276 hfill = re.compile(r'\\hfill')
2277 dotfill = re.compile(r'\\dotfill')
2278 hrulefill = re.compile(r'\\hrulefill')
2281 i = find_token(document.body, "\\InsetSpace", i)
2284 if hfill.search(document.body[i]):
2285 document.body[i] = \
2286 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2289 if dotfill.search(document.body[i]):
2290 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2291 '\\begin_inset ERT\nstatus collapsed\n\n' \
2292 '\\begin_layout Standard\n\n\n\\backslash\n' \
2293 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2294 subst = subst.split('\n')
2295 document.body[i : i+1] = subst
2298 if hrulefill.search(document.body[i]):
2299 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2300 '\\begin_inset ERT\nstatus collapsed\n\n' \
2301 '\\begin_layout Standard\n\n\n\\backslash\n' \
2302 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2303 subst = subst.split('\n')
2304 document.body[i : i+1] = subst
2309 def revert_hspace(document):
2310 ' Revert \\InsetSpace \\hspace{} to ERT '
2312 hspace = re.compile(r'\\hspace{}')
2313 hstar = re.compile(r'\\hspace\*{}')
2315 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2318 length = get_value(document.body, '\\length', i+1)
2320 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2322 del document.body[i+1]
2324 if hstar.search(document.body[i]):
2325 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2326 '\\begin_inset ERT\nstatus collapsed\n\n' \
2327 '\\begin_layout Standard\n\n\n\\backslash\n' \
2328 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2329 subst = subst.split('\n')
2330 document.body[i : i+1] = subst
2331 addedLines += len(subst) - 1
2334 if hspace.search(document.body[i]):
2335 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2336 '\\begin_inset ERT\nstatus collapsed\n\n' \
2337 '\\begin_layout Standard\n\n\n\\backslash\n' \
2338 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2339 subst = subst.split('\n')
2340 document.body[i : i+1] = subst
2341 addedLines += len(subst) - 1
2347 def revert_protected_hfill(document):
2348 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2351 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2354 j = find_end_of_inset(document.body, i)
2356 document.warning("Malformed LyX document: Could not find end of space inset.")
2358 del document.body[j]
2359 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2360 '\\begin_inset ERT\nstatus collapsed\n\n' \
2361 '\\begin_layout Standard\n\n\n\\backslash\n' \
2362 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2363 subst = subst.split('\n')
2364 document.body[i : i+1] = subst
2368 def revert_leftarrowfill(document):
2369 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2372 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2375 j = find_end_of_inset(document.body, i)
2377 document.warning("Malformed LyX document: Could not find end of space inset.")
2379 del document.body[j]
2380 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2381 '\\begin_inset ERT\nstatus collapsed\n\n' \
2382 '\\begin_layout Standard\n\n\n\\backslash\n' \
2383 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2384 subst = subst.split('\n')
2385 document.body[i : i+1] = subst
2389 def revert_rightarrowfill(document):
2390 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2393 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2396 j = find_end_of_inset(document.body, i)
2398 document.warning("Malformed LyX document: Could not find end of space inset.")
2400 del document.body[j]
2401 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2402 '\\begin_inset ERT\nstatus collapsed\n\n' \
2403 '\\begin_layout Standard\n\n\n\\backslash\n' \
2404 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2405 subst = subst.split('\n')
2406 document.body[i : i+1] = subst
2410 def revert_upbracefill(document):
2411 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2414 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2417 j = find_end_of_inset(document.body, i)
2419 document.warning("Malformed LyX document: Could not find end of space inset.")
2421 del document.body[j]
2422 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2423 '\\begin_inset ERT\nstatus collapsed\n\n' \
2424 '\\begin_layout Standard\n\n\n\\backslash\n' \
2425 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2426 subst = subst.split('\n')
2427 document.body[i : i+1] = subst
2431 def revert_downbracefill(document):
2432 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2435 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2438 j = find_end_of_inset(document.body, i)
2440 document.warning("Malformed LyX document: Could not find end of space inset.")
2442 del document.body[j]
2443 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2444 '\\begin_inset ERT\nstatus collapsed\n\n' \
2445 '\\begin_layout Standard\n\n\n\\backslash\n' \
2446 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2447 subst = subst.split('\n')
2448 document.body[i : i+1] = subst
2452 def revert_local_layout(document):
2453 ' Revert local layout headers.'
2456 i = find_token(document.header, "\\begin_local_layout", i)
2459 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2461 # this should not happen
2463 document.header[i : j + 1] = []
2466 def convert_pagebreaks(document):
2467 ' Convert inline Newpage insets to new format '
2470 i = find_token(document.body, '\\newpage', i)
2473 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2477 i = find_token(document.body, '\\pagebreak', i)
2480 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2484 i = find_token(document.body, '\\clearpage', i)
2487 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2491 i = find_token(document.body, '\\cleardoublepage', i)
2494 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2498 def revert_pagebreaks(document):
2499 ' Revert \\begin_inset Newpage to previous inline format '
2502 i = find_token(document.body, '\\begin_inset Newpage', i)
2505 j = find_end_of_inset(document.body, i)
2507 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2509 del document.body[j]
2510 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2511 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2512 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2513 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2516 def convert_linebreaks(document):
2517 ' Convert inline Newline insets to new format '
2520 i = find_token(document.body, '\\newline', i)
2523 document.body[i:i+1] = ['\\begin_inset Newline newline',
2527 i = find_token(document.body, '\\linebreak', i)
2530 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2534 def revert_linebreaks(document):
2535 ' Revert \\begin_inset Newline to previous inline format '
2538 i = find_token(document.body, '\\begin_inset Newline', i)
2541 j = find_end_of_inset(document.body, i)
2543 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2545 del document.body[j]
2546 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2547 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2550 def convert_japanese_plain(document):
2551 ' Set language japanese-plain to japanese '
2553 if document.language == "japanese-plain":
2554 document.language = "japanese"
2555 i = find_token(document.header, "\\language", 0)
2557 document.header[i] = "\\language japanese"
2560 j = find_token(document.body, "\\lang japanese-plain", j)
2563 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2567 def revert_pdfpages(document):
2568 ' Revert pdfpages external inset to ERT '
2571 i = find_token(document.body, "\\begin_inset External", i)
2574 j = find_end_of_inset(document.body, i)
2576 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2579 if get_value(document.body, 'template', i, j) == "PDFPages":
2580 filename = get_value(document.body, 'filename', i, j)
2582 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2583 for k in range(i, j):
2584 m = r.match(document.body[k])
2587 angle = get_value(document.body, 'rotateAngle', i, j)
2588 width = get_value(document.body, 'width', i, j)
2589 height = get_value(document.body, 'height', i, j)
2590 scale = get_value(document.body, 'scale', i, j)
2591 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2595 options += ",angle=" + angle
2597 options += "angle=" + angle
2600 options += ",width=" + convert_len(width)
2602 options += "width=" + convert_len(width)
2605 options += ",height=" + convert_len(height)
2607 options += "height=" + convert_len(height)
2610 options += ",scale=" + scale
2612 options += "scale=" + scale
2613 if keepAspectRatio != '':
2615 options += ",keepaspectratio"
2617 options += "keepaspectratio"
2619 options = '[' + options + ']'
2620 del document.body[i+1:j+1]
2621 document.body[i:i+1] = ['\\begin_inset ERT',
2624 '\\begin_layout Standard',
2627 'includepdf' + options + '{' + filename + '}',
2631 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2637 def revert_mexican(document):
2638 ' Set language Spanish(Mexico) to Spanish '
2640 if document.language == "spanish-mexico":
2641 document.language = "spanish"
2642 i = find_token(document.header, "\\language", 0)
2644 document.header[i] = "\\language spanish"
2647 j = find_token(document.body, "\\lang spanish-mexico", j)
2650 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2654 def remove_embedding(document):
2655 ' Remove embed tag from all insets '
2656 revert_inset_embedding(document, 'Graphics')
2657 revert_inset_embedding(document, 'External')
2658 revert_inset_embedding(document, 'CommandInset include')
2659 revert_inset_embedding(document, 'CommandInset bibtex')
2662 def revert_master(document):
2663 ' Remove master param '
2664 i = find_token(document.header, "\\master", 0)
2666 del document.header[i]
2669 def revert_graphics_group(document):
2670 ' Revert group information from graphics insets '
2673 i = find_token(document.body, "\\begin_inset Graphics", i)
2676 j = find_end_of_inset(document.body, i)
2678 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2681 k = find_token(document.body, " groupId", i, j)
2685 del document.body[k]
2689 def update_apa_styles(document):
2690 ' Replace obsolete styles '
2692 if document.textclass != "apa":
2695 obsoletedby = { "Acknowledgments": "Acknowledgements",
2696 "Section*": "Section",
2697 "Subsection*": "Subsection",
2698 "Subsubsection*": "Subsubsection",
2699 "Paragraph*": "Paragraph",
2700 "Subparagraph*": "Subparagraph"}
2703 i = find_token(document.body, "\\begin_layout", i)
2707 layout = document.body[i][14:]
2708 if layout in obsoletedby:
2709 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2714 def convert_paper_sizes(document):
2715 ' exchange size options legalpaper and executivepaper to correct order '
2716 # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2719 i = find_token(document.header, "\\papersize executivepaper", 0)
2721 document.header[i] = "\\papersize legalpaper"
2723 j = find_token(document.header, "\\papersize legalpaper", 0)
2725 document.header[j] = "\\papersize executivepaper"
2728 def revert_paper_sizes(document):
2729 ' exchange size options legalpaper and executivepaper to correct order '
2732 i = find_token(document.header, "\\papersize executivepaper", 0)
2734 document.header[i] = "\\papersize legalpaper"
2736 j = find_token(document.header, "\\papersize legalpaper", 0)
2738 document.header[j] = "\\papersize executivepaper"
2741 def convert_InsetSpace(document):
2742 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2745 i = find_token(document.body, "\\begin_inset Space", i)
2748 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2751 def revert_InsetSpace(document):
2752 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2755 i = find_token(document.body, "\\begin_inset space", i)
2758 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2761 def convert_display_enum(document):
2762 " Convert 'display foo' to 'display false/true'"
2765 i = find_token(document.body, "\tdisplay", i)
2768 val = get_value(document.body, 'display', i)
2770 document.body[i] = document.body[i].replace('none', 'false')
2771 if val == "default":
2772 document.body[i] = document.body[i].replace('default', 'true')
2773 if val == "monochrome":
2774 document.body[i] = document.body[i].replace('monochrome', 'true')
2775 if val == "grayscale":
2776 document.body[i] = document.body[i].replace('grayscale', 'true')
2778 document.body[i] = document.body[i].replace('color', 'true')
2779 if val == "preview":
2780 document.body[i] = document.body[i].replace('preview', 'true')
2784 def revert_display_enum(document):
2785 " Revert 'display false/true' to 'display none/color'"
2788 i = find_token(document.body, "\tdisplay", i)
2791 val = get_value(document.body, 'display', i)
2793 document.body[i] = document.body[i].replace('false', 'none')
2795 document.body[i] = document.body[i].replace('true', 'default')
2799 def remove_fontsCJK(document):
2800 ' Remove font_cjk param '
2801 i = find_token(document.header, "\\font_cjk", 0)
2803 del document.header[i]
2806 def convert_plain_layout(document):
2807 " Convert 'PlainLayout' to 'Plain Layout'"
2810 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2813 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2814 '\\begin_layout Plain Layout')
2818 def revert_plain_layout(document):
2819 " Convert 'PlainLayout' to 'Plain Layout'"
2822 i = find_token(document.body, '\\begin_layout Plain Layout', i)
2825 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2826 '\\begin_layout PlainLayout')
2830 def revert_plainlayout(document):
2831 " Convert 'PlainLayout' to 'Plain Layout'"
2834 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2837 # This will be incorrect for some document classes, since Standard is not always
2838 # the default. But (a) it is probably the best we can do and (b) it will actually
2839 # work, in fact, since an unknown layout will be converted to default.
2840 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2841 '\\begin_layout Standard')
2845 def revert_polytonicgreek(document):
2846 "Set language polytonic Greek to Greek"
2848 if document.language == "polutonikogreek":
2849 document.language = "greek"
2850 i = find_token(document.header, "\\language", 0)
2852 document.header[i] = "\\language greek"
2855 j = find_token(document.body, "\\lang polutonikogreek", j)
2858 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2862 def revert_removed_modules(document):
2865 i = find_token(document.header, "\\begin_remove_modules", i)
2868 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
2870 # this should not happen
2872 document.header[i : j + 1] = []
2875 def add_plain_layout(document):
2878 i = find_token(document.body, "\\begin_layout", i)
2881 if len(document.body[i].split()) == 1:
2882 document.body[i] = "\\begin_layout Plain Layout"
2889 supported_versions = ["1.6.0","1.6"]
2890 convert = [[277, [fix_wrong_tables]],
2891 [278, [close_begin_deeper]],
2892 [279, [long_charstyle_names]],
2893 [280, [axe_show_label]],
2896 [283, [convert_flex]],
2900 [287, [convert_wrapfig_options]],
2901 [288, [convert_inset_command]],
2902 [289, [convert_latexcommand_index]],
2905 [292, [convert_japanese_cjk]],
2907 [294, [convert_pdf_options]],
2908 [295, [convert_htmlurl, convert_url]],
2909 [296, [convert_include]],
2910 [297, [convert_usorbian]],
2916 [303, [convert_serbocroatian]],
2917 [304, [convert_framed_notes]],
2924 [311, [convert_ams_classes]],
2926 [313, [convert_module_names]],
2929 [316, [convert_subfig]],
2932 [319, [convert_spaceinset, convert_hfill]],
2934 [321, [convert_tablines]],
2935 [322, [convert_plain_layout]],
2936 [323, [convert_pagebreaks]],
2937 [324, [convert_linebreaks]],
2938 [325, [convert_japanese_plain]],
2941 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
2944 [331, [convert_ltcaption]],
2946 [333, [update_apa_styles]],
2947 [334, [convert_paper_sizes]],
2948 [335, [convert_InsetSpace]],
2950 [337, [convert_display_enum]],
2953 [340, [add_plain_layout]]
2956 revert = [[339, []],
2957 [338, [revert_removed_modules]],
2958 [337, [revert_polytonicgreek]],
2959 [336, [revert_display_enum]],
2960 [335, [remove_fontsCJK]],
2961 [334, [revert_InsetSpace]],
2962 [333, [revert_paper_sizes]],
2964 [331, [revert_graphics_group]],
2965 [330, [revert_ltcaption]],
2966 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
2967 [328, [revert_master]],
2969 [326, [revert_mexican]],
2970 [325, [revert_pdfpages]],
2972 [323, [revert_linebreaks]],
2973 [322, [revert_pagebreaks]],
2974 [321, [revert_local_layout, revert_plain_layout]],
2975 [320, [revert_tablines]],
2976 [319, [revert_protected_hfill]],
2977 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
2978 [317, [remove_extra_embedded_files]],
2979 [316, [revert_wrapplacement]],
2980 [315, [revert_subfig]],
2981 [314, [revert_colsep, revert_plainlayout]],
2983 [312, [revert_module_names]],
2984 [311, [revert_rotfloat, revert_widesideways]],
2985 [310, [revert_external_embedding]],
2986 [309, [revert_btprintall]],
2987 [308, [revert_nocite]],
2988 [307, [revert_serbianlatin]],
2989 [306, [revert_slash, revert_nobreakdash]],
2990 [305, [revert_interlingua]],
2991 [304, [revert_bahasam]],
2992 [303, [revert_framed_notes]],
2994 [301, [revert_latin, revert_samin]],
2995 [300, [revert_linebreak]],
2996 [299, [revert_pagebreak]],
2997 [298, [revert_hyperlinktype]],
2998 [297, [revert_macro_optional_params]],
2999 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3000 [295, [revert_include]],
3001 [294, [revert_href, revert_url]],
3002 [293, [revert_pdf_options_2]],
3003 [292, [revert_inset_info]],
3004 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3005 [290, [revert_vietnamese]],
3006 [289, [revert_wraptable]],
3007 [288, [revert_latexcommand_index]],
3008 [287, [revert_inset_command]],
3009 [286, [revert_wrapfig_options]],
3010 [285, [revert_pdf_options]],
3011 [284, [remove_inzip_options]],
3013 [282, [revert_flex]],
3015 [280, [revert_begin_modules]],
3016 [279, [revert_show_label]],
3017 [278, [revert_long_charstyle_names]],
3023 if __name__ == "__main__":