1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2008 The LyX Team <lyx-devel@lists.lyx.org>
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 """ Convert files to the file format generated by lyx 1.6"""
25 from parser_tools import find_token, find_end_of, find_tokens, get_value
26 from unicode_symbols import unicode_reps
28 ####################################################################
29 # Private helper functions
32 def get_value_string(lines, token, start, end = 0, trim = False, default = ""):
33 """ get_value_string(lines, token, start[[, end], trim, default]) -> string
35 Return tokens after token as string, in lines, where
36 token is the first element. When trim is used, the first and last character
37 of the string is trimmed."""
39 val = get_value(lines, token, start, end, "")
47 def find_end_of_inset(lines, i):
48 " Find end of inset, where lines[i] is included."
49 return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
53 # document.body[i] = wrap_insert_ert(...)
54 # wrap_into_ert may returns a multiline string, which should NOT appear
55 # in document.body. Instead, do something like this:
56 # subst = wrap_inset_ert(...)
57 # subst = subst.split('\n')
58 # document.body[i:i+1] = subst
60 # where the last statement resets the counter to accord with the added
62 def wrap_into_ert(string, src, dst):
63 '''Within string, replace occurrences of src with dst, wrapped into ERT
64 E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is:
65 sch<ERT>\\backslash</ERT>"on'''
66 return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
67 + dst + '\n\\end_layout\n\\end_inset\n')
69 def put_cmd_in_ert(string):
70 for rep in unicode_reps:
71 string = string.replace(rep[1], rep[0].replace('\\\\', '\\'))
72 string = string.replace('\\', "\\backslash\n")
73 string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n" \
74 + string + "\n\\end_layout\n\\end_inset"
77 def add_to_preamble(document, text):
78 """ Add text to the preamble if it is not already there.
79 Only the first line is checked!"""
81 if find_token(document.preamble, text[0], 0) != -1:
84 document.preamble.extend(text)
86 def insert_to_preamble(index, document, text):
87 """ Insert text to the preamble at a given line"""
89 document.preamble.insert(index, text)
91 # Convert a LyX length into a LaTeX length
93 units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
94 "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
95 "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
97 # Convert LyX units to LaTeX units
98 for unit in list(units.keys()):
99 if len.find(unit) != -1:
100 len = '%f' % (len2value(len) / 100)
101 len = len.strip('0') + units[unit]
106 # Return the value of len without the unit in numerical form.
108 result = re.search('([+-]?[0-9.]+)', len)
110 return float(result.group(1))
111 # No number means 1.0
114 # Unfortunately, this doesn't really work, since Standard isn't always default.
115 # But it's as good as we can do right now.
116 def find_default_layout(document, start, end):
117 l = find_token(document.body, "\\begin_layout Standard", start, end)
119 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
121 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
124 def get_option(document, m, option, default):
125 l = document.body[m].find(option)
128 val = document.body[m][l:].split('"')[1]
131 def remove_option(document, m, option):
132 l = document.body[m].find(option)
134 val = document.body[m][l:].split('"')[1]
135 document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
138 def set_option(document, m, option, value):
139 l = document.body[m].find(option)
141 oldval = document.body[m][l:].split('"')[1]
142 l = l + len(option + '="')
143 document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
145 document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
149 def extract_argument(line):
150 'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
155 bracere = re.compile("(\s*)(.*)")
156 n = bracere.match(line)
157 whitespace = n.group(1)
160 if brace != "[" and brace != "{":
184 # We never found the matching brace
185 # So, to be on the safe side, let's just return everything
186 # which will then get wrapped as ERT
188 return (line[:pos + 1], line[pos + 1:])
191 def latex2ert(line, isindex):
192 '''Converts LaTeX commands into ERT. line may well be a multi-line
193 string when it is returned.'''
198 ## FIXME Escaped \ ??
199 # This regex looks for a LaTeX command---i.e., something of the form
200 # "\alPhaStuFF", or "\X", where X is any character---where the command
201 # may also be preceded by an additional backslash, which is how it would
202 # appear (e.g.) in an InsetIndex.
203 labelre = re.compile(r'(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)')
205 m = labelre.match(line)
212 (arg, rest) = extract_argument(end)
217 # If we wanted to put labels into an InsetLabel, for example, then we
218 # would just need to test here for cmd == "label" and then take some
219 # appropriate action, i.e., to use arg to get the content and then
220 # wrap it appropriately.
221 cmd = put_cmd_in_ert(cmd)
222 retval += "\n" + cmd + "\n"
224 m = labelre.match(line)
225 # put all remaining braces in ERT
226 line = wrap_into_ert(line, '}', '}')
227 line = wrap_into_ert(line, '{', '{')
229 # active character that is not available in all font encodings
230 line = wrap_into_ert(line, '|', '|')
236 #Might should do latex2ert first, then deal with stuff that DOESN'T
237 #end up inside ERT. That routine could be modified so that it returned
238 #a list of lines, and we could then skip ERT bits and only deal with
240 def latex2lyx(data, isindex):
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.
244 The bool isindex specifies whether we are in an index macro (which
245 has some specific active characters that need to be ERTed).'''
251 # Convert LaTeX to Unicode
252 # Commands of this sort need to be checked to make sure they are
253 # followed by a non-alpha character, lest we replace too much.
254 hardone = re.compile(r'^\\\\[a-zA-Z]+$')
256 for rep in unicode_reps:
257 if hardone.match(rep[0]):
260 pos = data.find(rep[0], pos)
263 nextpos = pos + len(rep[0])
264 if nextpos < len(data) and data[nextpos].isalpha():
265 # not the end of that command
268 data = data[:pos] + rep[1] + data[nextpos:]
271 data = data.replace(rep[0], rep[1])
275 data = wrap_into_ert(data, r'\"', '"')
277 data = data.replace('\\\\', '\\')
280 mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
281 lines = data.split('\n')
283 #document.warning("LINE: " + line)
284 #document.warning(str(i) + ":" + document.body[i])
285 #document.warning("LAST: " + document.body[-1])
290 f = m.group(2).replace('\\\\', '\\')
294 s = latex2ert(s, isindex)
295 subst = s.split('\n')
297 retval.append("\\begin_inset Formula " + f)
298 retval.append("\\end_inset")
300 # Handle whatever is left, which is just text
301 g = latex2ert(g, isindex)
302 subst = g.split('\n')
307 def lyxline2latex(document, line, inert):
308 'Convert some LyX stuff into corresponding LaTeX stuff line-wise, as best we can.'
309 if line.startswith("\\begin_inset Formula"):
311 elif line.startswith("\\begin_inset Quotes"):
312 # For now, we do a very basic reversion. Someone who understands
313 # quotes is welcome to fix it up.
314 qtype = line[20:].strip()
328 elif line.isspace() or \
329 line.startswith("\\begin_layout") or \
330 line.startswith("\\end_layout") or \
331 line.startswith("\\begin_inset") or \
332 line.startswith("\\end_inset") or \
333 line.startswith("\\lang") or \
334 line.strip() == "status collapsed" or \
335 line.strip() == "status open":
339 # this needs to be added to the preamble because of cases like
340 # \textmu, \textbackslash, etc.
341 add_to_preamble(document, ['% added by lyx2lyx for converted entries',
342 '\\@ifundefined{textmu}',
343 ' {\\usepackage{textcomp}}{}'])
344 # a lossless reversion is not possible
345 # try at least to handle some common insets and settings
347 line = line.replace(r'\backslash', '\\')
349 line = line.replace('&', '\\&{}')
350 line = line.replace('#', '\\#{}')
351 line = line.replace('^', '\\^{}')
352 line = line.replace('%', '\\%{}')
353 line = line.replace('_', '\\_{}')
354 line = line.replace('$', '\\${}')
356 # Do the LyX text --> LaTeX conversion
357 for rep in unicode_reps:
358 line = line.replace(rep[1], rep[0].replace('\\\\', '\\') + "{}")
359 line = line.replace(r'\backslash', r'\textbackslash{}')
360 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
361 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
362 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
363 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
364 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
365 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
366 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
367 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
368 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
372 def lyx2latex(document, lines):
373 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
374 # clean up multiline stuff
378 for curline in range(len(lines)):
379 line = lines[curline]
380 if line.startswith("\\begin_inset ERT"):
381 # We don't want to replace things inside ERT, so figure out
382 # where the end of the inset is.
383 ert_end = find_end_of_inset(lines, curline + 1)
385 inert = ert_end >= curline
386 content += lyxline2latex(document, lines[curline], inert)
391 ####################################################################
393 def convert_ltcaption(document):
396 i = find_token(document.body, "\\begin_inset Tabular", i)
399 j = find_end_of_inset(document.body, i + 1)
401 document.warning("Malformed LyX document: Could not find end of tabular.")
405 nrows = int(document.body[i+1].split('"')[3])
406 ncols = int(document.body[i+1].split('"')[5])
409 for k in range(nrows):
410 m = find_token(document.body, "<row", m)
413 for k in range(ncols):
414 m = find_token(document.body, "<cell", m)
416 mend = find_token(document.body, "</cell>", m + 1)
417 # first look for caption insets
418 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
419 # then look for ERT captions
421 mcap = find_token(document.body, "caption", m + 1, mend)
423 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
426 if caption == 'true':
428 set_option(document, r, 'caption', 'true')
429 set_option(document, m, 'multicolumn', '1')
430 set_option(document, m, 'bottomline', 'false')
431 set_option(document, m, 'topline', 'false')
432 set_option(document, m, 'rightline', 'false')
433 set_option(document, m, 'leftline', 'false')
434 #j = find_end_of_inset(document.body, j + 1)
436 set_option(document, m, 'multicolumn', '2')
443 #FIXME Use of wrap_into_ert can confuse lyx2lyx
444 def revert_ltcaption(document):
447 i = find_token(document.body, "\\begin_inset Tabular", i)
450 j = find_end_of_inset(document.body, i + 1)
452 document.warning("Malformed LyX document: Could not find end of tabular.")
457 nrows = int(document.body[i+1].split('"')[3])
458 ncols = int(document.body[i+1].split('"')[5])
460 for k in range(nrows):
461 m = find_token(document.body, "<row", m)
462 caption = get_option(document, m, 'caption', 'false')
463 if caption == 'true':
464 remove_option(document, m, 'caption')
465 for k in range(ncols):
466 m = find_token(document.body, "<cell", m)
467 remove_option(document, m, 'multicolumn')
469 m = find_token(document.body, "\\begin_inset Caption", m)
472 m = find_end_of_inset(document.body, m + 1)
473 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
479 def convert_tablines(document):
482 i = find_token(document.body, "\\begin_inset Tabular", i)
484 # LyX 1.3 inserted an extra space between \begin_inset
485 # and Tabular so let us try if this is the case and fix it.
486 i = find_token(document.body, "\\begin_inset Tabular", i)
490 document.body[i] = "\\begin_inset Tabular"
491 j = find_end_of_inset(document.body, i + 1)
493 document.warning("Malformed LyX document: Could not find end of tabular.")
498 nrows = int(document.body[i+1].split('"')[3])
499 ncols = int(document.body[i+1].split('"')[5])
502 for k in range(ncols):
503 m = find_token(document.body, "<column", m)
504 left = get_option(document, m, 'leftline', 'false')
505 right = get_option(document, m, 'rightline', 'false')
506 col_info.append([left, right])
507 remove_option(document, m, 'leftline')
508 remove_option(document, m, 'rightline')
512 for k in range(nrows):
513 m = find_token(document.body, "<row", m)
514 top = get_option(document, m, 'topline', 'false')
515 bottom = get_option(document, m, 'bottomline', 'false')
516 row_info.append([top, bottom])
517 remove_option(document, m, 'topline')
518 remove_option(document, m, 'bottomline')
523 for k in range(nrows*ncols):
524 m = find_token(document.body, "<cell", m)
525 mc_info.append(get_option(document, m, 'multicolumn', '0'))
528 for l in range(nrows):
529 for k in range(ncols):
530 m = find_token(document.body, '<cell', m)
531 if mc_info[l*ncols + k] == '0':
532 r = set_option(document, m, 'topline', row_info[l][0])
533 r = set_option(document, m, 'bottomline', row_info[l][1])
534 r = set_option(document, m, 'leftline', col_info[k][0])
535 r = set_option(document, m, 'rightline', col_info[k][1])
536 elif mc_info[l*ncols + k] == '1':
538 while s < ncols and mc_info[l*ncols + s] == '2':
540 if s < ncols and mc_info[l*ncols + s] != '1':
541 r = set_option(document, m, 'rightline', col_info[k][1])
542 if k > 0 and mc_info[l*ncols + k - 1] == '0':
543 r = set_option(document, m, 'leftline', col_info[k][0])
548 def revert_tablines(document):
551 i = find_token(document.body, "\\begin_inset Tabular", i)
554 j = find_end_of_inset(document.body, i)
556 document.warning("Malformed LyX document: Could not find end of tabular.")
561 nrows = int(document.body[i+1].split('"')[3])
562 ncols = int(document.body[i+1].split('"')[5])
565 for k in range(nrows*ncols):
566 m = find_token(document.body, "<cell", m)
567 top = get_option(document, m, 'topline', 'false')
568 bottom = get_option(document, m, 'bottomline', 'false')
569 left = get_option(document, m, 'leftline', 'false')
570 right = get_option(document, m, 'rightline', 'false')
571 lines.append([top, bottom, left, right])
574 # we will want to ignore longtable captions
577 for k in range(nrows):
578 m = find_token(document.body, "<row", m)
579 caption = get_option(document, m, 'caption', 'false')
580 caption_info.append([caption])
585 for k in range(ncols):
586 m = find_token(document.body, "<column", m)
588 for l in range(nrows):
589 left = lines[l*ncols + k][2]
590 if left == 'false' and caption_info[l] == 'false':
592 set_option(document, m, 'leftline', left)
594 for l in range(nrows):
595 right = lines[l*ncols + k][3]
596 if right == 'false' and caption_info[l] == 'false':
598 set_option(document, m, 'rightline', right)
602 for k in range(nrows):
603 m = find_token(document.body, "<row", m)
605 for l in range(ncols):
606 top = lines[k*ncols + l][0]
609 if caption_info[k] == 'false':
611 set_option(document, m, 'topline', top)
613 for l in range(ncols):
614 bottom = lines[k*ncols + l][1]
615 if bottom == 'false':
617 if caption_info[k] == 'false':
619 set_option(document, m, 'bottomline', bottom)
625 def fix_wrong_tables(document):
628 i = find_token(document.body, "\\begin_inset Tabular", i)
631 j = find_end_of_inset(document.body, i + 1)
633 document.warning("Malformed LyX document: Could not find end of tabular.")
638 nrows = int(document.body[i+1].split('"')[3])
639 ncols = int(document.body[i+1].split('"')[5])
641 for l in range(nrows):
643 for k in range(ncols):
644 m = find_token(document.body, '<cell', m)
646 if document.body[m].find('multicolumn') != -1:
647 multicol_cont = int(document.body[m].split('"')[1])
649 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
650 document.body[m] = document.body[m][:5] + document.body[m][21:]
653 prev_multicolumn = multicol_cont
660 def close_begin_deeper(document):
664 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
669 if document.body[i][:13] == "\\begin_deeper":
676 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
679 def long_charstyle_names(document):
682 i = find_token(document.body, "\\begin_inset CharStyle", i)
685 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
688 def revert_long_charstyle_names(document):
691 i = find_token(document.body, "\\begin_inset CharStyle", i)
694 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
698 def axe_show_label(document):
701 i = find_token(document.body, "\\begin_inset CharStyle", i)
704 if document.body[i + 1].find("show_label") != -1:
705 if document.body[i + 1].find("true") != -1:
706 document.body[i + 1] = "status open"
707 del document.body[ i + 2]
709 if document.body[i + 1].find("false") != -1:
710 document.body[i + 1] = "status collapsed"
711 del document.body[ i + 2]
713 document.warning("Malformed LyX document: show_label neither false nor true.")
715 document.warning("Malformed LyX document: show_label missing in CharStyle.")
720 def revert_show_label(document):
723 i = find_token(document.body, "\\begin_inset CharStyle", i)
726 if document.body[i + 1].find("status open") != -1:
727 document.body.insert(i + 1, "show_label true")
729 if document.body[i + 1].find("status collapsed") != -1:
730 document.body.insert(i + 1, "show_label false")
732 document.warning("Malformed LyX document: no legal status line in CharStyle.")
735 def revert_begin_modules(document):
738 i = find_token(document.header, "\\begin_modules", i)
741 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
743 # this should not happen
745 document.header[i : j + 1] = []
747 def convert_flex(document):
748 "Convert CharStyle to Flex"
751 i = find_token(document.body, "\\begin_inset CharStyle", i)
754 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
756 def revert_flex(document):
757 "Revert Flex to CharStyle"
760 i = find_token(document.body, "\\begin_inset Flex", i)
763 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
766 def revert_pdf_options(document):
767 "Revert PDF options for hyperref."
768 # store the PDF options and delete the entries from the Lyx file
776 bookmarksnumbered = ""
778 bookmarksopenlevel = ""
786 i = find_token(document.header, "\\use_hyperref", i)
788 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
789 del document.header[i]
790 i = find_token(document.header, "\\pdf_store_options", i)
792 del document.header[i]
793 i = find_token(document.header, "\\pdf_title", 0)
795 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
796 title = ' pdftitle={' + title + '}'
797 del document.header[i]
798 i = find_token(document.header, "\\pdf_author", 0)
800 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
802 author = ' pdfauthor={' + author + '}'
804 author = ',\n pdfauthor={' + author + '}'
805 del document.header[i]
806 i = find_token(document.header, "\\pdf_subject", 0)
808 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
809 if title == "" and author == "":
810 subject = ' pdfsubject={' + subject + '}'
812 subject = ',\n pdfsubject={' + subject + '}'
813 del document.header[i]
814 i = find_token(document.header, "\\pdf_keywords", 0)
816 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
817 if title == "" and author == "" and subject == "":
818 keywords = ' pdfkeywords={' + keywords + '}'
820 keywords = ',\n pdfkeywords={' + keywords + '}'
821 del document.header[i]
822 i = find_token(document.header, "\\pdf_bookmarks", 0)
824 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
825 bookmarks = ',\n bookmarks=' + bookmarks
826 del document.header[i]
827 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
829 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
830 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
831 del document.header[i]
832 i = find_token(document.header, "\\pdf_bookmarksopen", i)
834 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
835 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
836 del document.header[i]
837 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
839 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
840 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
841 del document.header[i]
842 i = find_token(document.header, "\\pdf_breaklinks", i)
844 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
845 breaklinks = ',\n breaklinks=' + breaklinks
846 del document.header[i]
847 i = find_token(document.header, "\\pdf_pdfborder", i)
849 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
850 if pdfborder == 'true':
851 pdfborder = ',\n pdfborder={0 0 0}'
853 pdfborder = ',\n pdfborder={0 0 1}'
854 del document.header[i]
855 i = find_token(document.header, "\\pdf_colorlinks", i)
857 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
858 colorlinks = ',\n colorlinks=' + colorlinks
859 del document.header[i]
860 i = find_token(document.header, "\\pdf_backref", i)
862 backref = get_value_string(document.header, '\\pdf_backref', 0)
863 backref = ',\n backref=' + backref
864 del document.header[i]
865 i = find_token(document.header, "\\pdf_pagebackref", i)
867 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
868 pagebackref = ',\n pagebackref=' + pagebackref
869 del document.header[i]
870 i = find_token(document.header, "\\pdf_pagemode", 0)
872 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
873 pagemode = ',\n pdfpagemode=' + pagemode
874 del document.header[i]
875 i = find_token(document.header, "\\pdf_quoted_options", 0)
877 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
878 if title == "" and author == "" and subject == "" and keywords == "":
879 otheroptions = ' ' + otheroptions
881 otheroptions = ',\n ' + otheroptions
882 del document.header[i]
884 # write to the preamble when hyperref was used
886 # preamble write preparations
887 # bookmark numbers are only output when they are turned on
888 if bookmarksopen == ',\n bookmarksopen=true':
889 bookmarksopen = bookmarksopen + bookmarksopenlevel
890 if bookmarks == ',\n bookmarks=true':
891 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
893 bookmarks = bookmarks
894 # hypersetup is only output when there are things to be set up
895 setupstart = '\\hypersetup{%\n'
897 if otheroptions == "" and title == "" and author == ""\
898 and subject == "" and keywords == "":
902 # babel must be loaded before hyperref and hyperref the first part
903 # of the preamble, like in LyX 1.6
904 insert_to_preamble(0, document,
905 '% Commands inserted by lyx2lyx for PDF properties\n'
906 + '\\usepackage{babel}\n'
907 + '\\usepackage[unicode=true'
926 def remove_inzip_options(document):
927 "Remove inzipName and embed options from the Graphics inset"
930 i = find_token(document.body, "\\begin_inset Graphics", i)
933 j = find_end_of_inset(document.body, i + 1)
936 document.warning("Malformed LyX document: Could not find end of graphics inset.")
939 # If there's a inzip param, just remove that
940 k = find_token(document.body, "\tinzipName", i + 1, j)
943 # embed option must follow the inzipName option
944 del document.body[k+1]
948 def convert_inset_command(document):
951 \begin_inset LatexCommand cmd
953 \begin_inset CommandInset InsetType
958 i = find_token(document.body, "\\begin_inset LatexCommand", i)
961 line = document.body[i]
962 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
966 #this is adapted from factory.cpp
967 if cmdName[0:4].lower() == "cite":
968 insetName = "citation"
969 elif cmdName == "url" or cmdName == "htmlurl":
971 elif cmdName[-3:] == "ref":
973 elif cmdName == "tableofcontents":
975 elif cmdName == "printnomenclature":
976 insetName = "nomencl_print"
977 elif cmdName == "printindex":
978 insetName = "index_print"
981 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
982 document.body[i : i+1] = insertion
985 def revert_inset_command(document):
988 \begin_inset CommandInset InsetType
991 \begin_inset LatexCommand cmd
992 Some insets may end up being converted to insets earlier versions of LyX
993 will not be able to recognize. Not sure what to do about that.
997 i = find_token(document.body, "\\begin_inset CommandInset", i)
1000 nextline = document.body[i+1]
1001 r = re.compile(r'LatexCommand\s+(.*)$')
1002 m = r.match(nextline)
1004 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
1007 cmdName = m.group(1)
1008 insertion = ["\\begin_inset LatexCommand " + cmdName]
1009 document.body[i : i+2] = insertion
1012 def convert_wrapfig_options(document):
1013 "Convert optional options for wrap floats (wrapfig)."
1014 # adds the tokens "lines", "placement", and "overhang"
1017 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1020 document.body.insert(i + 1, "lines 0")
1021 j = find_token(document.body, "placement", i)
1022 # placement can be already set or not; if not, set it
1024 document.body.insert(i + 3, "overhang 0col%")
1026 document.body.insert(i + 2, "placement o")
1027 document.body.insert(i + 3, "overhang 0col%")
1031 def revert_wrapfig_options(document):
1032 "Revert optional options for wrap floats (wrapfig)."
1035 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1038 j = find_end_of_inset(document.body, i)
1040 document.warning("Can't find end of Wrap inset at line " + str(i))
1043 k = find_default_layout(document, i, j)
1045 document.warning("Can't find default layout for Wrap figure!")
1048 # Options should be between i and k now
1049 l = find_token(document.body, "lines", i, k)
1051 document.warning("Can't find lines option for Wrap figure!")
1054 m = find_token(document.body, "overhang", i + 1, k)
1056 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1059 # Do these in reverse order
1060 del document.body[m]
1061 del document.body[l]
1065 def convert_latexcommand_index(document):
1066 "Convert from LatexCommand form to collapsible form."
1068 r1 = re.compile('name "(.*)"')
1070 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1073 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1076 j = find_end_of_inset(document.body, i + 1)
1078 document.warning("Unable to find end of index inset at line " + str(i) + "!")
1081 m = r1.match(document.body[i + 2])
1083 document.warning("Unable to match: " + document.body[i+2])
1084 # this can happen with empty index insets!
1087 fullcontent = m.group(1)
1088 linelist = latex2lyx(fullcontent, True)
1089 #document.warning(fullcontent)
1091 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1092 linelist + ["\\end_layout"]
1093 document.body[i : j] = linelist
1094 i += len(linelist) - (j - i)
1097 def revert_latexcommand_index(document):
1098 "Revert from collapsible form to LatexCommand form."
1101 i = find_token(document.body, "\\begin_inset Index", i)
1104 j = find_end_of_inset(document.body, i + 1)
1108 content = lyx2latex(document, document.body[i:j])
1110 content = content.replace('"', r'\"')
1111 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1112 "name " + '"' + content + '"', ""]
1116 def revert_wraptable(document):
1117 "Revert wrap table to wrap figure."
1120 i = find_token(document.body, "\\begin_inset Wrap table", i)
1123 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1127 def revert_vietnamese(document):
1128 "Set language Vietnamese to English"
1129 # Set document language from Vietnamese to English
1131 if document.language == "vietnamese":
1132 document.language = "english"
1133 i = find_token(document.header, "\\language", 0)
1135 document.header[i] = "\\language english"
1138 j = find_token(document.body, "\\lang vietnamese", j)
1141 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1145 def convert_japanese_cjk(document):
1146 "Set language japanese to japanese-cjk"
1147 # Set document language from japanese-plain to japanese
1149 if document.language == "japanese":
1150 document.language = "japanese-cjk"
1151 i = find_token(document.header, "\\language", 0)
1153 document.header[i] = "\\language japanese-cjk"
1156 j = find_token(document.body, "\\lang japanese", j)
1159 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1163 def revert_japanese(document):
1164 "Set language japanese-plain to japanese"
1165 # Set document language from japanese-plain to japanese
1167 if document.language == "japanese-plain":
1168 document.language = "japanese"
1169 i = find_token(document.header, "\\language", 0)
1171 document.header[i] = "\\language japanese"
1174 j = find_token(document.body, "\\lang japanese-plain", j)
1177 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1181 def revert_japanese_cjk(document):
1182 "Set language japanese-cjk to japanese"
1183 # Set document language from japanese-plain to japanese
1185 if document.language == "japanese-cjk":
1186 document.language = "japanese"
1187 i = find_token(document.header, "\\language", 0)
1189 document.header[i] = "\\language japanese"
1192 j = find_token(document.body, "\\lang japanese-cjk", j)
1195 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1199 def revert_japanese_encoding(document):
1200 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1201 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1203 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1205 document.header[i] = "\\inputencoding EUC-JP"
1207 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1209 document.header[j] = "\\inputencoding JIS"
1211 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1212 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1213 document.header[k] = "\\inputencoding UTF8"
1216 def revert_inset_info(document):
1217 'Replace info inset with its content'
1220 i = find_token(document.body, '\\begin_inset Info', i)
1223 j = find_end_of_inset(document.body, i + 1)
1226 document.warning("Malformed LyX document: Could not find end of Info inset.")
1231 for k in range(i, j+1):
1232 if document.body[k].startswith("arg"):
1233 arg = document.body[k][3:].strip()
1234 # remove embracing quotation marks
1237 if arg[len(arg) - 1] == '"':
1238 arg = arg[:len(arg) - 1]
1239 # \" to straight quote
1240 arg = arg.replace(r'\"', '"')
1242 arg = arg.replace(r'\\', "\\backslash\n")
1243 if document.body[k].startswith("type"):
1244 type = document.body[k][4:].strip().strip('"')
1245 # I think there is a newline after \\end_inset, which should be removed.
1246 if document.body[j + 1].strip() == "":
1247 document.body[i : (j + 2)] = [type + ':' + arg]
1249 document.body[i : (j + 1)] = [type + ':' + arg]
1252 def convert_pdf_options(document):
1253 # Set the pdfusetitle tag, delete the pdf_store_options,
1254 # set quotes for bookmarksopenlevel"
1255 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1257 k = find_token(document.header, "\\use_hyperref", 0)
1258 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1259 k = find_token(document.header, "\\pdf_store_options", 0)
1261 del document.header[k]
1262 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1264 document.header[i] = document.header[i].replace('"', '')
1267 def revert_pdf_options_2(document):
1268 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1269 k = find_token(document.header, "\\use_hyperref", 0)
1270 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1272 del document.header[i]
1273 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1275 values = document.header[i].split()
1276 values[1] = ' "' + values[1] + '"'
1277 document.header[i] = ''.join(values)
1280 def convert_htmlurl(document):
1281 'Convert "htmlurl" to "href" insets for docbook'
1282 if document.backend != "docbook":
1286 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1289 document.body[i] = "\\begin_inset CommandInset href"
1290 document.body[i + 1] = "LatexCommand href"
1294 def convert_url(document):
1295 'Convert url insets to url charstyles'
1296 if document.backend == "docbook":
1300 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1303 n = find_token(document.body, "name", i)
1305 # place the URL name in typewriter before the new URL insert
1306 # grab the name 'bla' from the e.g. the line 'name "bla"',
1307 # therefore start with the 6th character
1308 name = document.body[n][6:-1]
1309 newname = [name + " "]
1310 document.body[i:i] = newname
1312 j = find_token(document.body, "target", i)
1314 document.warning("Malformed LyX document: Can't find target for url inset")
1317 target = document.body[j][8:-1]
1318 k = find_token(document.body, "\\end_inset", j)
1320 document.warning("Malformed LyX document: Can't find end of url inset")
1323 newstuff = ["\\begin_inset Flex URL",
1324 "status collapsed", "",
1325 "\\begin_layout Standard",
1330 document.body[i:k] = newstuff
1331 i = i + len(newstuff)
1333 def convert_ams_classes(document):
1334 tc = document.textclass
1335 if (tc != "amsart" and tc != "amsart-plain" and
1336 tc != "amsart-seq" and tc != "amsbook"):
1338 if tc == "amsart-plain":
1339 document.textclass = "amsart"
1340 document.set_textclass()
1341 document.add_module("Theorems (Starred)")
1343 if tc == "amsart-seq":
1344 document.textclass = "amsart"
1345 document.set_textclass()
1346 document.add_module("Theorems (AMS)")
1348 #Now we want to see if any of the environments in the extended theorems
1349 #module were used in this document. If so, we'll add that module, too.
1350 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1351 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1354 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1357 i = find_token(document.body, "\\begin_layout", i)
1360 m = r.match(document.body[i])
1362 # This is an empty layout
1363 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1367 if layouts.count(m) != 0:
1368 document.add_module("Theorems (AMS-Extended)")
1372 def revert_href(document):
1373 'Reverts hyperlink insets (href) to url insets (url)'
1376 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1379 document.body[i : i + 2] = \
1380 ["\\begin_inset CommandInset url", "LatexCommand url"]
1383 def revert_url(document):
1384 'Reverts Flex URL insets to old-style URL insets'
1387 i = find_token(document.body, "\\begin_inset Flex URL", i)
1390 j = find_end_of_inset(document.body, i)
1392 document.warning("Can't find end of inset in revert_url!")
1394 k = find_default_layout(document, i, j)
1396 document.warning("Can't find default layout in revert_url!")
1399 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1400 if l == -1 or l >= j:
1401 document.warning("Can't find end of default layout in revert_url!")
1404 # OK, so the inset's data is between lines k and l.
1405 data = " ".join(document.body[k+1:l])
1407 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1409 document.body[i:j+1] = newinset
1410 i = i + len(newinset)
1413 def convert_include(document):
1414 'Converts include insets to new format.'
1416 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1418 i = find_token(document.body, "\\begin_inset Include", i)
1421 line = document.body[i]
1422 previewline = document.body[i + 1]
1425 document.warning("Unable to match line " + str(i) + " of body!")
1431 insertion = ["\\begin_inset CommandInset include",
1432 "LatexCommand " + cmd, previewline,
1433 "filename \"" + fn + "\""]
1436 insertion.append("lstparams " + '"' + opt + '"')
1438 document.body[i : i + 2] = insertion
1442 def revert_include(document):
1443 'Reverts include insets to old format.'
1445 r0 = re.compile('preview.*')
1446 r1 = re.compile('LatexCommand (.+)')
1447 r2 = re.compile('filename "(.+)"')
1448 r3 = re.compile('lstparams "(.*)"')
1450 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1454 m = r1.match(document.body[nextline])
1456 document.warning("Malformed LyX document: No LatexCommand line for `" +
1457 document.body[i] + "' on line " + str(i) + ".")
1462 if r0.match(document.body[nextline]):
1463 previewline = document.body[nextline]
1467 m = r2.match(document.body[nextline])
1469 document.warning("Malformed LyX document: No filename line for `" + \
1470 document.body[i] + "' on line " + str(i) + ".")
1476 if (cmd == "lstinputlisting"):
1477 m = r3.match(document.body[nextline])
1479 options = m.group(1)
1482 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1484 newline += ("[" + options + "]")
1485 insertion = [newline]
1486 if previewline != "":
1487 insertion.append(previewline)
1488 document.body[i : nextline] = insertion
1492 def revert_albanian(document):
1493 "Set language Albanian to English"
1495 if document.language == "albanian":
1496 document.language = "english"
1497 i = find_token(document.header, "\\language", 0)
1499 document.header[i] = "\\language english"
1502 j = find_token(document.body, "\\lang albanian", j)
1505 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1509 def revert_lowersorbian(document):
1510 "Set language lower Sorbian to English"
1512 if document.language == "lowersorbian":
1513 document.language = "english"
1514 i = find_token(document.header, "\\language", 0)
1516 document.header[i] = "\\language english"
1519 j = find_token(document.body, "\\lang lowersorbian", j)
1522 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1526 def revert_uppersorbian(document):
1527 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1529 if document.language == "uppersorbian":
1530 document.language = "usorbian"
1531 i = find_token(document.header, "\\language", 0)
1533 document.header[i] = "\\language usorbian"
1536 j = find_token(document.body, "\\lang uppersorbian", j)
1539 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1543 def convert_usorbian(document):
1544 "Set language usorbian to uppersorbian"
1546 if document.language == "usorbian":
1547 document.language = "uppersorbian"
1548 i = find_token(document.header, "\\language", 0)
1550 document.header[i] = "\\language uppersorbian"
1553 j = find_token(document.body, "\\lang usorbian", j)
1556 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1560 def convert_macro_global(document):
1561 "Remove TeX code command \global when it is in front of a macro"
1562 # math macros are nowadays already defined \global, so that an additional
1563 # \global would make the document uncompilable, see
1564 # http://www.lyx.org/trac/ticket/5371
1565 # We're looking for something like this:
1569 # \begin_layout Plain Layout
1579 # \begin_inset FormulaMacro
1580 # \renewcommand{\foo}{123}
1584 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1587 # if i <= 13, then there isn't enough room for the ERT
1591 if document.body[i-6] == "global":
1592 del document.body[i-13 : i]
1598 def revert_macro_optional_params(document):
1599 "Convert macro definitions with optional parameters into ERTs"
1600 # Stub to convert macro definitions with one or more optional parameters
1601 # into uninterpreted ERT insets
1604 def revert_hyperlinktype(document):
1605 'Reverts hyperlink type'
1609 i = find_token(document.body, "target", i)
1612 j = find_token(document.body, "type", i)
1616 del document.body[j]
1620 def revert_pagebreak(document):
1621 'Reverts pagebreak to ERT'
1624 i = find_token(document.body, "\\pagebreak", i)
1627 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1628 '\\begin_layout Standard\n\n\n\\backslash\n' \
1629 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1633 def revert_linebreak(document):
1634 'Reverts linebreak to ERT'
1637 i = find_token(document.body, "\\linebreak", i)
1640 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1641 '\\begin_layout Standard\n\n\n\\backslash\n' \
1642 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1646 def revert_latin(document):
1647 "Set language Latin to English"
1649 if document.language == "latin":
1650 document.language = "english"
1651 i = find_token(document.header, "\\language", 0)
1653 document.header[i] = "\\language english"
1656 j = find_token(document.body, "\\lang latin", j)
1659 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1663 def revert_samin(document):
1664 "Set language North Sami to English"
1666 if document.language == "samin":
1667 document.language = "english"
1668 i = find_token(document.header, "\\language", 0)
1670 document.header[i] = "\\language english"
1673 j = find_token(document.body, "\\lang samin", j)
1676 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1680 def convert_serbocroatian(document):
1681 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1683 if document.language == "serbocroatian":
1684 document.language = "croatian"
1685 i = find_token(document.header, "\\language", 0)
1687 document.header[i] = "\\language croatian"
1690 j = find_token(document.body, "\\lang serbocroatian", j)
1693 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1697 def convert_framed_notes(document):
1698 "Convert framed notes to boxes. "
1701 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1704 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1713 'height_special "totalheight"']
1714 document.body[i:i+1] = subst
1718 def convert_module_names(document):
1719 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1720 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1721 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1722 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1723 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1724 modlist = document.get_module_list()
1725 if len(modlist) == 0:
1729 if mod in modulemap:
1730 newmodlist.append(modulemap[mod])
1732 document.warning("Can't find module %s in the module map!" % mod)
1733 newmodlist.append(mod)
1734 document.set_module_list(newmodlist)
1737 def revert_module_names(document):
1738 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1739 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1740 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1741 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1742 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1743 modlist = document.get_module_list()
1744 if len(modlist) == 0:
1748 if mod in modulemap:
1749 newmodlist.append(modulemap[mod])
1751 document.warning("Can't find module %s in the module map!" % mod)
1752 newmodlist.append(mod)
1753 document.set_module_list(newmodlist)
1756 def revert_colsep(document):
1757 i = find_token(document.header, "\\columnsep", 0)
1760 colsepline = document.header[i]
1761 r = re.compile(r'\\columnsep (.*)')
1762 m = r.match(colsepline)
1764 document.warning("Malformed column separation line!")
1767 del document.header[i]
1768 #it seems to be safe to add the package even if it is already used
1769 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1771 add_to_preamble(document, pretext)
1774 def revert_framed_notes(document):
1775 "Revert framed boxes to notes. "
1778 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1782 j = find_end_of_inset(document.body, i + 1)
1785 document.warning("Malformed LyX document: Could not find end of Box inset.")
1788 k = find_token(document.body, "status", i + 1, j)
1790 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1793 status = document.body[k]
1794 l = find_default_layout(document, i + 1, j)
1796 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1799 m = find_token(document.body, "\\end_layout", i + 1, j)
1801 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1804 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1805 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1806 if ibox == -1 and pbox == -1:
1807 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1808 del document.body[i+1:k]
1810 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1811 subst1 = [document.body[l],
1812 "\\begin_inset Note Shaded",
1814 '\\begin_layout Standard']
1815 document.body[l:l + 1] = subst1
1816 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1817 document.body[m:m + 1] = subst2
1821 def revert_slash(document):
1822 'Revert \\SpecialChar \\slash{} to ERT'
1824 while i < len(document.body):
1825 m = re.match(r'(.*)\\SpecialChar \\slash{}(.*)', document.body[i])
1830 '\\begin_inset ERT',
1831 'status collapsed', '',
1832 '\\begin_layout Standard',
1833 '', '', '\\backslash',
1838 document.body[i: i+1] = subst
1844 def revert_nobreakdash(document):
1845 'Revert \\SpecialChar \\nobreakdash- to ERT'
1847 while i < len(document.body):
1848 m = re.match(r'(.*)\\SpecialChar \\nobreakdash-(.*)', document.body[i])
1853 '\\begin_inset ERT',
1854 'status collapsed', '',
1855 '\\begin_layout Standard', '', '',
1861 document.body[i: i+1] = subst
1863 j = find_token(document.header, "\\use_amsmath", 0)
1865 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1868 document.header[j] = "\\use_amsmath 2"
1873 #Returns number of lines added/removed
1874 def revert_nocite_key(body, start, end):
1875 'key "..." -> \nocite{...}'
1876 r = re.compile(r'^key "(.*)"')
1880 m = r.match(body[i])
1882 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1883 j += 1 # because we added a line
1884 i += 2 # skip that line
1887 j -= 1 # because we deleted a line
1888 # no need to change i, since it now points to the next line
1892 def revert_nocite(document):
1893 "Revert LatexCommand nocite to ERT"
1896 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1899 if (document.body[i+1] != "LatexCommand nocite"):
1900 # note that we already incremented i
1903 insetEnd = find_end_of_inset(document.body, i)
1905 #this should not happen
1906 document.warning("End of CommandInset citation not found in revert_nocite!")
1909 paramLocation = i + 2 #start of the inset's parameters
1911 document.body[i:i+2] = \
1912 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1913 # that added two lines
1916 #print insetEnd, document.body[i: insetEnd + 1]
1917 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1918 #print insetEnd, document.body[i: insetEnd + 1]
1919 document.body.insert(insetEnd, "\\end_layout")
1920 document.body.insert(insetEnd + 1, "")
1924 def revert_btprintall(document):
1925 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1926 i = find_token(document.header, '\\use_bibtopic', 0)
1928 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1930 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1932 while i < len(document.body):
1933 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1936 j = find_end_of_inset(document.body, i + 1)
1938 #this should not happen
1939 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1940 j = len(document.body)
1941 # this range isn't really right, but it should be OK, since we shouldn't
1942 # see more than one matching line in each inset
1944 for k in range(i, j):
1945 if (document.body[k] == 'btprint "btPrintAll"'):
1946 del document.body[k]
1947 subst = ["\\begin_inset ERT",
1948 "status collapsed", "",
1949 "\\begin_layout Standard", "",
1954 document.body[i:i] = subst
1955 addlines = addedlines + len(subst) - 1
1959 def revert_bahasam(document):
1960 "Set language Bahasa Malaysia to Bahasa Indonesia"
1962 if document.language == "bahasam":
1963 document.language = "bahasa"
1964 i = find_token(document.header, "\\language", 0)
1966 document.header[i] = "\\language bahasa"
1969 j = find_token(document.body, "\\lang bahasam", j)
1972 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1976 def revert_interlingua(document):
1977 "Set language Interlingua to English"
1979 if document.language == "interlingua":
1980 document.language = "english"
1981 i = find_token(document.header, "\\language", 0)
1983 document.header[i] = "\\language english"
1986 j = find_token(document.body, "\\lang interlingua", j)
1989 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1993 def revert_serbianlatin(document):
1994 "Set language Serbian-Latin to Croatian"
1996 if document.language == "serbian-latin":
1997 document.language = "croatian"
1998 i = find_token(document.header, "\\language", 0)
2000 document.header[i] = "\\language croatian"
2003 j = find_token(document.body, "\\lang serbian-latin", j)
2006 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
2010 def revert_rotfloat(document):
2011 " Revert sideways custom floats. "
2014 # whitespace intended (exclude \\begin_inset FloatList)
2015 i = find_token(document.body, "\\begin_inset Float ", i)
2018 line = document.body[i]
2019 r = re.compile(r'\\begin_inset Float (.*)$')
2022 document.warning("Unable to match line " + str(i) + " of body!")
2025 floattype = m.group(1)
2026 if floattype == "figure" or floattype == "table":
2029 j = find_end_of_inset(document.body, i)
2031 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
2035 if get_value(document.body, 'sideways', i, j) == "false":
2038 l = find_default_layout(document, i + 1, j)
2040 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2043 subst = ['\\begin_layout Standard',
2044 '\\begin_inset ERT',
2045 'status collapsed', '',
2046 '\\begin_layout Standard', '', '',
2048 'end{sideways' + floattype + '}',
2049 '\\end_layout', '', '\\end_inset']
2050 document.body[j : j+1] = subst
2051 addedLines = len(subst) - 1
2052 del document.body[i+1 : l]
2053 addedLines -= (l-1) - (i+1)
2054 subst = ['\\begin_inset ERT', 'status collapsed', '',
2055 '\\begin_layout Standard', '', '', '\\backslash',
2056 'begin{sideways' + floattype + '}',
2057 '\\end_layout', '', '\\end_inset', '',
2059 document.body[i : i+1] = subst
2060 addedLines += len(subst) - 1
2061 if floattype == "algorithm":
2062 add_to_preamble(document,
2063 ['% Commands inserted by lyx2lyx for sideways algorithm float',
2064 '\\usepackage{rotfloat}',
2065 '\\floatstyle{ruled}',
2066 '\\newfloat{algorithm}{tbp}{loa}',
2067 '\\floatname{algorithm}{Algorithm}'])
2069 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
2073 def revert_widesideways(document):
2074 " Revert wide sideways floats. "
2077 # whitespace intended (exclude \\begin_inset FloatList)
2078 i = find_token(document.body, '\\begin_inset Float ', i)
2081 line = document.body[i]
2082 r = re.compile(r'\\begin_inset Float (.*)$')
2085 document.warning("Unable to match line " + str(i) + " of body!")
2088 floattype = m.group(1)
2089 if floattype != "figure" and floattype != "table":
2092 j = find_end_of_inset(document.body, i)
2094 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2097 if get_value(document.body, 'sideways', i, j) == "false" or \
2098 get_value(document.body, 'wide', i, j) == "false":
2101 l = find_default_layout(document, i + 1, j)
2103 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2106 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2107 'status collapsed', '',
2108 '\\begin_layout Standard', '', '', '\\backslash',
2109 'end{sideways' + floattype + '*}',
2110 '\\end_layout', '', '\\end_inset']
2111 document.body[j : j+1] = subst
2112 addedLines = len(subst) - 1
2113 del document.body[i+1:l-1]
2114 addedLines -= (l-1) - (i+1)
2115 subst = ['\\begin_inset ERT', 'status collapsed', '',
2116 '\\begin_layout Standard', '', '', '\\backslash',
2117 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2118 '\\end_inset', '', '\\end_layout', '']
2119 document.body[i : i+1] = subst
2120 addedLines += len(subst) - 1
2121 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2125 def revert_inset_embedding(document, type):
2126 ' Remove embed tag from certain type of insets'
2129 i = find_token(document.body, "\\begin_inset %s" % type, i)
2132 j = find_end_of_inset(document.body, i)
2134 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2137 k = find_token(document.body, "\tembed", i, j)
2139 k = find_token(document.body, "embed", i, j)
2141 del document.body[k]
2145 def revert_external_embedding(document):
2146 ' Remove embed tag from external inset '
2147 revert_inset_embedding(document, 'External')
2150 def convert_subfig(document):
2151 " Convert subfigures to subfloats. "
2155 i = find_token(document.body, '\\begin_inset Graphics', i)
2158 endInset = find_end_of_inset(document.body, i)
2160 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2163 k = find_token(document.body, '\tsubcaption', i, endInset)
2167 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2171 caption = document.body[l][16:].strip('"')
2172 del document.body[l]
2174 del document.body[k]
2176 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2177 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2178 '', '\\begin_layout Plain Layout'] + latex2lyx(caption, False) + \
2179 [ '\\end_layout', '', '\\end_inset', '',
2180 '\\end_layout', '', '\\begin_layout Plain Layout']
2181 document.body[i : i] = subst
2182 addedLines += len(subst)
2183 endInset += addedLines
2184 subst = ['', '\\end_inset', '', '\\end_layout']
2185 document.body[endInset : endInset] = subst
2186 addedLines += len(subst)
2190 def revert_subfig(document):
2191 " Revert subfloats. "
2194 # whitespace intended (exclude \\begin_inset FloatList)
2195 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2201 j = find_end_of_inset(document.body, i)
2203 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2204 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2206 continue # this will get us back to the outer loop, since j == -1
2207 # look for embedded float (= subfloat)
2208 # whitespace intended (exclude \\begin_inset FloatList)
2209 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2212 # is the subfloat aligned?
2213 al = find_token(document.body, '\\align ', k - 1, j)
2217 if get_value(document.body, '\\align', al) == "center":
2218 alignment_beg = "\\backslash\nbegin{centering}"
2219 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2220 elif get_value(document.body, '\\align', al) == "left":
2221 alignment_beg = "\\backslash\nbegin{raggedright}"
2222 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2223 elif get_value(document.body, '\\align', al) == "right":
2224 alignment_beg = "\\backslash\nbegin{raggedleft}"
2225 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2226 l = find_end_of_inset(document.body, k)
2228 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2231 continue # escape to the outer loop
2232 m = find_default_layout(document, k + 1, l)
2234 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2239 capend = find_end_of_inset(document.body, cap)
2241 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2245 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2247 lblend = find_end_of_inset(document.body, lbl + 1)
2249 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2251 for line in document.body[lbl:lblend + 1]:
2252 if line.startswith('name '):
2253 label = line.split()[1].strip('"')
2260 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2262 optend = find_end_of_inset(document.body, opt)
2264 document.warning("Malformed LyX document: Missing '\\end_inset' (OptArg).")
2266 optc = find_default_layout(document, opt, optend)
2268 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2270 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2271 for line in document.body[optc:optcend]:
2272 if not line.startswith('\\'):
2273 shortcap += line.strip()
2277 for line in document.body[cap:capend]:
2278 if line in document.body[lbl:lblend]:
2280 elif line in document.body[opt:optend]:
2284 caption += lyxline2latex(document, line, inert)
2286 caption += "\n\\backslash\nlabel{" + label + "}"
2287 subst = '\\begin_layout PlainLayout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2288 '\\begin_layout PlainLayout\n\n}' + alignment_end + \
2289 '\n\\end_layout\n\n\\end_inset\n\n' \
2290 '\\end_layout\n\n\\begin_layout PlainLayout\n'
2291 subst = subst.split('\n')
2292 document.body[l : l+1] = subst
2293 addedLines = len(subst) - 1
2294 # this is before l and so is unchanged by the multiline insertion
2296 del document.body[cap:capend+1]
2297 addedLines -= (capend + 1 - cap)
2298 del document.body[k+1:m-1]
2299 addedLines -= (m - 1 - (k + 1))
2300 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2301 '\\begin_layout PlainLayout\n\n' + alignment_beg + '\n\\backslash\n' \
2303 if len(shortcap) > 0:
2304 insertion = insertion + "[" + shortcap + "]"
2305 if len(caption) > 0:
2306 insertion = insertion + "[" + caption + "]"
2307 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2308 insertion = insertion.split('\n')
2309 document.body[k : k + 1] = insertion
2310 addedLines += len(insertion) - 1
2311 al = find_token(document.body, '\\align ', k - 1, j + addedLines)
2313 del document.body[al]
2315 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2319 def revert_wrapplacement(document):
2320 " Revert placement options wrap floats (wrapfig). "
2323 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2326 e = find_end_of_inset(document.body, i)
2327 j = find_token(document.body, "placement", i + 1, e)
2329 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2332 r = re.compile("placement (o|i|l|r|O|I|L|R)")
2333 m = r.match(document.body[j])
2335 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2337 document.body[j] = "placement " + m.group(1).lower()
2341 def remove_extra_embedded_files(document):
2342 " Remove \extra_embedded_files from buffer params "
2343 i = find_token(document.header, '\\extra_embedded_files', 0)
2346 document.header.pop(i)
2349 def convert_spaceinset(document):
2350 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2352 while i < len(document.body):
2353 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2357 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2358 document.body[i: i+1] = subst
2364 def revert_spaceinset(document):
2365 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2368 i = find_token(document.body, "\\begin_inset Space", i)
2371 j = find_end_of_inset(document.body, i)
2373 document.warning("Malformed LyX document: Could not find end of space inset.")
2376 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2377 del document.body[j]
2380 def convert_hfill(document):
2381 " Convert hfill to space inset "
2384 i = find_token(document.body, "\\hfill", i)
2387 subst = document.body[i].replace('\\hfill', \
2388 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2389 subst = subst.split('\n')
2390 document.body[i : i+1] = subst
2394 def revert_hfills(document):
2395 ' Revert \\hfill commands '
2396 hfill = re.compile(r'\\hfill')
2397 dotfill = re.compile(r'\\dotfill')
2398 hrulefill = re.compile(r'\\hrulefill')
2401 i = find_token(document.body, "\\InsetSpace", i)
2404 if hfill.search(document.body[i]):
2405 document.body[i] = \
2406 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2409 if dotfill.search(document.body[i]):
2410 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2411 '\\begin_inset ERT\nstatus collapsed\n\n' \
2412 '\\begin_layout Standard\n\n\n\\backslash\n' \
2413 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2414 subst = subst.split('\n')
2415 document.body[i : i+1] = subst
2418 if hrulefill.search(document.body[i]):
2419 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2420 '\\begin_inset ERT\nstatus collapsed\n\n' \
2421 '\\begin_layout Standard\n\n\n\\backslash\n' \
2422 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2423 subst = subst.split('\n')
2424 document.body[i : i+1] = subst
2429 def revert_hspace(document):
2430 ' Revert \\InsetSpace \\hspace{} to ERT '
2432 hspace = re.compile(r'\\hspace{}')
2433 hstar = re.compile(r'\\hspace\*{}')
2435 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2438 length = get_value(document.body, '\\length', i+1)
2440 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2442 del document.body[i+1]
2444 if hstar.search(document.body[i]):
2445 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2446 '\\begin_inset ERT\nstatus collapsed\n\n' \
2447 '\\begin_layout Standard\n\n\n\\backslash\n' \
2448 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2449 subst = subst.split('\n')
2450 document.body[i : i+1] = subst
2451 addedLines += len(subst) - 1
2454 if hspace.search(document.body[i]):
2455 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2456 '\\begin_inset ERT\nstatus collapsed\n\n' \
2457 '\\begin_layout Standard\n\n\n\\backslash\n' \
2458 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2459 subst = subst.split('\n')
2460 document.body[i : i+1] = subst
2461 addedLines += len(subst) - 1
2467 def revert_protected_hfill(document):
2468 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2471 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2474 j = find_end_of_inset(document.body, i)
2476 document.warning("Malformed LyX document: Could not find end of space inset.")
2479 del document.body[j]
2480 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2481 '\\begin_inset ERT\nstatus collapsed\n\n' \
2482 '\\begin_layout Standard\n\n\n\\backslash\n' \
2483 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2484 subst = subst.split('\n')
2485 document.body[i : i+1] = subst
2489 def revert_leftarrowfill(document):
2490 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2493 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2496 j = find_end_of_inset(document.body, i)
2498 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 \\leftarrowfill{}', \
2503 '\\begin_inset ERT\nstatus collapsed\n\n' \
2504 '\\begin_layout Standard\n\n\n\\backslash\n' \
2505 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2506 subst = subst.split('\n')
2507 document.body[i : i+1] = subst
2511 def revert_rightarrowfill(document):
2512 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2515 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2518 j = find_end_of_inset(document.body, i)
2520 document.warning("Malformed LyX document: Could not find end of space inset.")
2523 del document.body[j]
2524 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2525 '\\begin_inset ERT\nstatus collapsed\n\n' \
2526 '\\begin_layout Standard\n\n\n\\backslash\n' \
2527 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2528 subst = subst.split('\n')
2529 document.body[i : i+1] = subst
2533 def revert_upbracefill(document):
2534 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2537 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2540 j = find_end_of_inset(document.body, i)
2542 document.warning("Malformed LyX document: Could not find end of space inset.")
2545 del document.body[j]
2546 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2547 '\\begin_inset ERT\nstatus collapsed\n\n' \
2548 '\\begin_layout Standard\n\n\n\\backslash\n' \
2549 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2550 subst = subst.split('\n')
2551 document.body[i : i+1] = subst
2555 def revert_downbracefill(document):
2556 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2559 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2562 j = find_end_of_inset(document.body, i)
2564 document.warning("Malformed LyX document: Could not find end of space inset.")
2567 del document.body[j]
2568 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2569 '\\begin_inset ERT\nstatus collapsed\n\n' \
2570 '\\begin_layout Standard\n\n\n\\backslash\n' \
2571 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2572 subst = subst.split('\n')
2573 document.body[i : i+1] = subst
2577 def revert_local_layout(document):
2578 ' Revert local layout headers.'
2581 i = find_token(document.header, "\\begin_local_layout", i)
2584 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2586 # this should not happen
2588 document.header[i : j + 1] = []
2591 def convert_pagebreaks(document):
2592 ' Convert inline Newpage insets to new format '
2595 i = find_token(document.body, '\\newpage', i)
2598 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2602 i = find_token(document.body, '\\pagebreak', i)
2605 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2609 i = find_token(document.body, '\\clearpage', i)
2612 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2616 i = find_token(document.body, '\\cleardoublepage', i)
2619 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2623 def revert_pagebreaks(document):
2624 ' Revert \\begin_inset Newpage to previous inline format '
2627 i = find_token(document.body, '\\begin_inset Newpage', i)
2630 j = find_end_of_inset(document.body, i)
2632 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2635 del document.body[j]
2636 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2637 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2638 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2639 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2642 def convert_linebreaks(document):
2643 ' Convert inline Newline insets to new format '
2646 i = find_token(document.body, '\\newline', i)
2649 document.body[i:i+1] = ['\\begin_inset Newline newline',
2653 i = find_token(document.body, '\\linebreak', i)
2656 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2660 def revert_linebreaks(document):
2661 ' Revert \\begin_inset Newline to previous inline format '
2664 i = find_token(document.body, '\\begin_inset Newline', i)
2667 j = find_end_of_inset(document.body, i)
2669 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2672 del document.body[j]
2673 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2674 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2677 def convert_japanese_plain(document):
2678 ' Set language japanese-plain to japanese '
2680 if document.language == "japanese-plain":
2681 document.language = "japanese"
2682 i = find_token(document.header, "\\language", 0)
2684 document.header[i] = "\\language japanese"
2687 j = find_token(document.body, "\\lang japanese-plain", j)
2690 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2694 def revert_pdfpages(document):
2695 ' Revert pdfpages external inset to ERT '
2698 i = find_token(document.body, "\\begin_inset External", i)
2701 j = find_end_of_inset(document.body, i)
2703 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2706 if get_value(document.body, 'template', i, j) == "PDFPages":
2707 filename = get_value(document.body, 'filename', i, j)
2709 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2710 for k in range(i, j):
2711 m = r.match(document.body[k])
2714 angle = get_value(document.body, 'rotateAngle', i, j)
2715 width = get_value(document.body, 'width', i, j)
2716 height = get_value(document.body, 'height', i, j)
2717 scale = get_value(document.body, 'scale', i, j)
2718 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2722 options += ",angle=" + angle
2724 options += "angle=" + angle
2727 options += ",width=" + convert_len(width)
2729 options += "width=" + convert_len(width)
2732 options += ",height=" + convert_len(height)
2734 options += "height=" + convert_len(height)
2737 options += ",scale=" + scale
2739 options += "scale=" + scale
2740 if keepAspectRatio != '':
2742 options += ",keepaspectratio"
2744 options += "keepaspectratio"
2746 options = '[' + options + ']'
2747 del document.body[i+1:j+1]
2748 document.body[i:i+1] = ['\\begin_inset ERT',
2751 '\\begin_layout Standard',
2754 'includepdf' + options + '{' + filename + '}',
2758 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2764 def revert_mexican(document):
2765 ' Set language Spanish(Mexico) to Spanish '
2767 if document.language == "spanish-mexico":
2768 document.language = "spanish"
2769 i = find_token(document.header, "\\language", 0)
2771 document.header[i] = "\\language spanish"
2774 j = find_token(document.body, "\\lang spanish-mexico", j)
2777 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2781 def remove_embedding(document):
2782 ' Remove embed tag from all insets '
2783 revert_inset_embedding(document, 'Graphics')
2784 revert_inset_embedding(document, 'External')
2785 revert_inset_embedding(document, 'CommandInset include')
2786 revert_inset_embedding(document, 'CommandInset bibtex')
2789 def revert_master(document):
2790 ' Remove master param '
2791 i = find_token(document.header, "\\master", 0)
2793 del document.header[i]
2796 def revert_graphics_group(document):
2797 ' Revert group information from graphics insets '
2800 i = find_token(document.body, "\\begin_inset Graphics", i)
2803 j = find_end_of_inset(document.body, i)
2805 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2808 k = find_token(document.body, " groupId", i, j)
2812 del document.body[k]
2816 def update_apa_styles(document):
2817 ' Replace obsolete styles '
2819 if document.textclass != "apa":
2822 obsoletedby = { "Acknowledgments": "Acknowledgements",
2823 "Section*": "Section",
2824 "Subsection*": "Subsection",
2825 "Subsubsection*": "Subsubsection",
2826 "Paragraph*": "Paragraph",
2827 "Subparagraph*": "Subparagraph"}
2830 i = find_token(document.body, "\\begin_layout", i)
2834 layout = document.body[i][14:]
2835 if layout in obsoletedby:
2836 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2841 def convert_paper_sizes(document):
2842 ' exchange size options legalpaper and executivepaper to correct order '
2843 # routine is needed to fix http://www.lyx.org/trac/ticket/4868
2846 i = find_token(document.header, "\\papersize executivepaper", 0)
2848 document.header[i] = "\\papersize legalpaper"
2850 j = find_token(document.header, "\\papersize legalpaper", 0)
2852 document.header[j] = "\\papersize executivepaper"
2855 def revert_paper_sizes(document):
2856 ' exchange size options legalpaper and executivepaper to correct order '
2859 i = find_token(document.header, "\\papersize executivepaper", 0)
2861 document.header[i] = "\\papersize legalpaper"
2863 j = find_token(document.header, "\\papersize legalpaper", 0)
2865 document.header[j] = "\\papersize executivepaper"
2868 def convert_InsetSpace(document):
2869 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2872 i = find_token(document.body, "\\begin_inset Space", i)
2875 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2878 def revert_InsetSpace(document):
2879 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2882 i = find_token(document.body, "\\begin_inset space", i)
2885 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2888 def convert_display_enum(document):
2889 " Convert 'display foo' to 'display false/true'"
2892 i = find_token(document.body, "\tdisplay", i)
2895 val = get_value(document.body, 'display', i)
2897 document.body[i] = document.body[i].replace('none', 'false')
2898 if val == "default":
2899 document.body[i] = document.body[i].replace('default', 'true')
2900 if val == "monochrome":
2901 document.body[i] = document.body[i].replace('monochrome', 'true')
2902 if val == "grayscale":
2903 document.body[i] = document.body[i].replace('grayscale', 'true')
2905 document.body[i] = document.body[i].replace('color', 'true')
2906 if val == "preview":
2907 document.body[i] = document.body[i].replace('preview', 'true')
2911 def revert_display_enum(document):
2912 " Revert 'display false/true' to 'display none/color'"
2915 i = find_token(document.body, "\tdisplay", i)
2918 val = get_value(document.body, 'display', i)
2920 document.body[i] = document.body[i].replace('false', 'none')
2922 document.body[i] = document.body[i].replace('true', 'default')
2926 def remove_fontsCJK(document):
2927 ' Remove font_cjk param '
2928 i = find_token(document.header, "\\font_cjk", 0)
2930 del document.header[i]
2933 def convert_plain_layout(document):
2934 " Convert 'PlainLayout' to 'Plain Layout'"
2937 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2940 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2941 '\\begin_layout Plain Layout')
2945 def revert_plain_layout(document):
2946 " Revert 'Plain Layout' to 'PlainLayout'"
2949 i = find_token(document.body, '\\begin_layout Plain Layout', i)
2952 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2953 '\\begin_layout PlainLayout')
2957 def revert_plainlayout(document):
2958 " Revert 'PlainLayout' to 'Standard'"
2961 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2964 # This will be incorrect for some document classes, since Standard is not always
2965 # the default. But (a) it is probably the best we can do and (b) it will actually
2966 # work, in fact, since an unknown layout will be converted to default.
2967 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2968 '\\begin_layout Standard')
2972 def revert_polytonicgreek(document):
2973 "Set language polytonic Greek to Greek"
2975 if document.language == "polutonikogreek":
2976 document.language = "greek"
2977 i = find_token(document.header, "\\language", 0)
2979 document.header[i] = "\\language greek"
2982 j = find_token(document.body, "\\lang polutonikogreek", j)
2985 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2989 def revert_removed_modules(document):
2992 i = find_token(document.header, "\\begin_remove_modules", i)
2995 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
2997 # this should not happen
2999 document.header[i : j + 1] = []
3002 def add_plain_layout(document):
3005 i = find_token(document.body, "\\begin_layout", i)
3008 if len(document.body[i].split()) == 1:
3009 document.body[i] = "\\begin_layout Plain Layout"
3013 def revert_tabulators(document):
3014 "Revert tabulators to 4 spaces"
3017 i = find_token(document.body, "\t", i)
3020 document.body[i] = document.body[i].replace("\t", " ")
3024 def revert_tabsize(document):
3025 "Revert the tabsize parameter of listings"
3029 # either it is the only parameter
3030 i = find_token(document.body, 'lstparams "tabsize=4"', i)
3032 del document.body[i]
3034 j = find_token(document.body, "lstparams", j)
3037 pos = document.body[j].find(",tabsize=")
3038 document.body[j] = document.body[j][:pos] + '"'
3043 def revert_mongolian(document):
3044 "Set language Mongolian to English"
3046 if document.language == "mongolian":
3047 document.language = "english"
3048 i = find_token(document.header, "\\language", 0)
3050 document.header[i] = "\\language english"
3053 j = find_token(document.body, "\\lang mongolian", j)
3056 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
3060 def revert_default_options(document):
3061 ' Remove param use_default_options '
3062 i = find_token(document.header, "\\use_default_options", 0)
3064 del document.header[i]
3067 def convert_default_options(document):
3068 ' Add param use_default_options and set it to false '
3069 i = find_token(document.header, "\\textclass", 0)
3071 document.warning("Malformed LyX document: Missing `\\textclass'.")
3073 document.header.insert(i, '\\use_default_options false')
3076 def revert_backref_options(document):
3077 ' Revert option pdf_backref=page to pagebackref '
3078 i = find_token(document.header, "\\pdf_backref page", 0)
3080 document.header[i] = "\\pdf_pagebackref true"
3083 def convert_backref_options(document):
3084 ' We have changed the option pagebackref to backref=true '
3085 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3087 document.header[i] = "\\pdf_backref page"
3088 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3090 del document.header[j]
3091 # backref=true was not a valid option, we meant backref=section
3092 k = find_token(document.header, "\\pdf_backref true", 0)
3093 if k != -1 and i != -1:
3094 del document.header[k]
3095 elif k != -1 and j != -1:
3096 document.header[k] = "\\pdf_backref section"
3099 def convert_charstyle_element(document):
3100 "Convert CharStyle to Element for docbook backend"
3101 if document.backend != "docbook":
3105 i = find_token(document.body, "\\begin_inset Flex CharStyle:", i)
3108 document.body[i] = document.body[i].replace('\\begin_inset Flex CharStyle:',
3109 '\\begin_inset Flex Element:')
3111 def revert_charstyle_element(document):
3112 "Convert Element to CharStyle for docbook backend"
3113 if document.backend != "docbook":
3117 i = find_token(document.body, "\\begin_inset Flex Element:", i)
3120 document.body[i] = document.body[i].replace('\\begin_inset Flex Element:',
3121 '\\begin_inset Flex CharStyle:')
3127 supported_versions = ["1.6.0","1.6"]
3128 convert = [[277, [fix_wrong_tables]],
3129 [278, [close_begin_deeper]],
3130 [279, [long_charstyle_names]],
3131 [280, [axe_show_label]],
3134 [283, [convert_flex]],
3138 [287, [convert_wrapfig_options]],
3139 [288, [convert_inset_command]],
3140 [289, [convert_latexcommand_index]],
3143 [292, [convert_japanese_cjk]],
3145 [294, [convert_pdf_options]],
3146 [295, [convert_htmlurl, convert_url]],
3147 [296, [convert_include]],
3148 [297, [convert_usorbian]],
3149 [298, [convert_macro_global]],
3154 [303, [convert_serbocroatian]],
3155 [304, [convert_framed_notes]],
3162 [311, [convert_ams_classes]],
3164 [313, [convert_module_names]],
3167 [316, [convert_subfig]],
3170 [319, [convert_spaceinset, convert_hfill]],
3172 [321, [convert_tablines]],
3173 [322, [convert_plain_layout]],
3174 [323, [convert_pagebreaks]],
3175 [324, [convert_linebreaks]],
3176 [325, [convert_japanese_plain]],
3179 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3182 [331, [convert_ltcaption]],
3184 [333, [update_apa_styles]],
3185 [334, [convert_paper_sizes]],
3186 [335, [convert_InsetSpace]],
3188 [337, [convert_display_enum]],
3191 [340, [add_plain_layout]],
3194 [343, [convert_default_options]],
3195 [344, [convert_backref_options]],
3196 [345, [convert_charstyle_element]]
3199 revert = [[344, [revert_charstyle_element]],
3200 [343, [revert_backref_options]],
3201 [342, [revert_default_options]],
3202 [341, [revert_mongolian]],
3203 [340, [revert_tabulators, revert_tabsize]],
3205 [338, [revert_removed_modules]],
3206 [337, [revert_polytonicgreek]],
3207 [336, [revert_display_enum]],
3208 [335, [remove_fontsCJK]],
3209 [334, [revert_InsetSpace]],
3210 [333, [revert_paper_sizes]],
3212 [331, [revert_graphics_group]],
3213 [330, [revert_ltcaption]],
3214 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
3215 [328, [revert_master]],
3217 [326, [revert_mexican]],
3218 [325, [revert_pdfpages]],
3220 [323, [revert_linebreaks]],
3221 [322, [revert_pagebreaks]],
3222 [321, [revert_local_layout, revert_plain_layout]],
3223 [320, [revert_tablines]],
3224 [319, [revert_protected_hfill]],
3225 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3226 [317, [remove_extra_embedded_files]],
3227 [316, [revert_wrapplacement]],
3228 [315, [revert_subfig]],
3229 [314, [revert_colsep, revert_plainlayout]],
3231 [312, [revert_module_names]],
3232 [311, [revert_rotfloat, revert_widesideways]],
3233 [310, [revert_external_embedding]],
3234 [309, [revert_btprintall]],
3235 [308, [revert_nocite]],
3236 [307, [revert_serbianlatin]],
3237 [306, [revert_slash, revert_nobreakdash]],
3238 [305, [revert_interlingua]],
3239 [304, [revert_bahasam]],
3240 [303, [revert_framed_notes]],
3242 [301, [revert_latin, revert_samin]],
3243 [300, [revert_linebreak]],
3244 [299, [revert_pagebreak]],
3245 [298, [revert_hyperlinktype]],
3246 [297, [revert_macro_optional_params]],
3247 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3248 [295, [revert_include]],
3249 [294, [revert_href, revert_url]],
3250 [293, [revert_pdf_options_2]],
3251 [292, [revert_inset_info]],
3252 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3253 [290, [revert_vietnamese]],
3254 [289, [revert_wraptable]],
3255 [288, [revert_latexcommand_index]],
3256 [287, [revert_inset_command]],
3257 [286, [revert_wrapfig_options]],
3258 [285, [revert_pdf_options]],
3259 [284, [remove_inzip_options]],
3261 [282, [revert_flex]],
3263 [280, [revert_begin_modules]],
3264 [279, [revert_show_label]],
3265 [278, [revert_long_charstyle_names]],
3271 if __name__ == "__main__":