1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2008 The LyX Team <lyx-devel@lists.lyx.org>
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 """ Convert files to the file format generated by lyx 1.6"""
25 from parser_tools import find_token, find_end_of, find_tokens, get_value
27 ####################################################################
28 # Private helper functions
31 def get_value_string(lines, token, start, end = 0, trim = False, default = ""):
32 """ get_value_string(lines, token, start[[, end], trim, default]) -> string
34 Return tokens after token as string, in lines, where
35 token is the first element. When trim is used, the first and last character
36 of the string is trimmed."""
38 val = get_value(lines, token, start, end, "")
46 def find_end_of_inset(lines, i):
47 " Find end of inset, where lines[i] is included."
48 return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
52 # document.body[i] = wrap_insert_ert(...)
53 # wrap_into_ert may returns a multiline string, which should NOT appear
54 # in document.body. Instead, do something like this:
55 # subst = wrap_inset_ert(...)
56 # subst = subst.split('\n')
57 # document.body[i:i+1] = subst
59 # where the last statement resets the counter to accord with the added
61 def wrap_into_ert(string, src, dst):
62 '''Within string, replace occurrences of src with dst, wrapped into ERT
63 E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is:
64 sch<ERT>\\backslash</ERT>"on'''
65 return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
66 + dst + '\n\\end_layout\n\\end_inset\n')
68 def put_cmd_in_ert(string):
69 for rep in unicode_reps:
70 string = string.replace(rep[1], rep[0].replace('\\\\', '\\'))
71 string = string.replace('\\', "\\backslash\n")
72 string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n" \
73 + string + "\n\\end_layout\n\\end_inset"
76 def add_to_preamble(document, text):
77 """ Add text to the preamble if it is not already there.
78 Only the first line is checked!"""
80 if find_token(document.preamble, text[0], 0) != -1:
83 document.preamble.extend(text)
85 def insert_to_preamble(index, document, text):
86 """ Insert text to the preamble at a given line"""
88 document.preamble.insert(index, text)
90 # Convert a LyX length into a LaTeX length
92 units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
93 "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
94 "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
96 # Convert LyX units to LaTeX units
97 for unit in units.keys():
98 if len.find(unit) != -1:
99 len = '%f' % (len2value(len) / 100)
100 len = len.strip('0') + units[unit]
105 # Return the value of len without the unit in numerical form.
107 result = re.search('([+-]?[0-9.]+)', len)
109 return float(result.group(1))
110 # No number means 1.0
113 # Unfortunately, this doesn't really work, since Standard isn't always default.
114 # But it's as good as we can do right now.
115 def find_default_layout(document, start, end):
116 l = find_token(document.body, "\\begin_layout Standard", start, end)
118 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
120 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
123 def get_option(document, m, option, default):
124 l = document.body[m].find(option)
127 val = document.body[m][l:].split('"')[1]
130 def remove_option(document, m, option):
131 l = document.body[m].find(option)
133 val = document.body[m][l:].split('"')[1]
134 document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
137 def set_option(document, m, option, value):
138 l = document.body[m].find(option)
140 oldval = document.body[m][l:].split('"')[1]
141 l = l + len(option + '="')
142 document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
144 document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
148 def read_unicodesymbols():
149 " Read the unicodesymbols list of unicode characters and corresponding commands."
150 pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
151 fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
153 # Two backslashes, followed by some non-word character, and then a character
154 # in brackets. The idea is to check for constructs like: \"{u}, which is how
155 # they are written in the unicodesymbols file; but they can also be written
156 # as: \"u or even \" u.
157 r = re.compile(r'\\\\(\W)\{(\w)\}')
158 for line in fp.readlines():
159 if line[0] != '#' and line.strip() != "":
160 line=line.replace(' "',' ') # remove all quotation marks with spaces before
161 line=line.replace('" ',' ') # remove all quotation marks with spaces after
162 line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
164 [ucs4,command,dead] = line.split(None,2)
165 if command[0:1] != "\\":
167 spec_chars.append([command, unichr(eval(ucs4))])
173 # If the character is a double-quote, then we need to escape it, too,
174 # since it is done that way in the LyX file.
175 if m.group(1) == "\"":
178 command += m.group(1) + m.group(2)
179 commandbl += m.group(1) + ' ' + m.group(2)
180 spec_chars.append([command, unichr(eval(ucs4))])
181 spec_chars.append([commandbl, unichr(eval(ucs4))])
186 def extract_argument(line):
187 'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
192 bracere = re.compile("(\s*)(.*)")
193 n = bracere.match(line)
194 whitespace = n.group(1)
197 if brace != "[" and brace != "{":
221 # We never found the matching brace
222 # So, to be on the safe side, let's just return everything
223 # which will then get wrapped as ERT
225 return (line[:pos + 1], line[pos + 1:])
228 def latex2ert(line, isindex):
229 '''Converts LaTeX commands into ERT. line may well be a multi-line
230 string when it is returned.'''
235 ## FIXME Escaped \ ??
236 # This regex looks for a LaTeX command---i.e., something of the form
237 # "\alPhaStuFF", or "\X", where X is any character---where the command
238 # may also be preceded by an additional backslash, which is how it would
239 # appear (e.g.) in an InsetIndex.
240 labelre = re.compile(r'(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)')
242 m = labelre.match(line)
249 (arg, rest) = extract_argument(end)
254 # If we wanted to put labels into an InsetLabel, for example, then we
255 # would just need to test here for cmd == "label" and then take some
256 # appropriate action, i.e., to use arg to get the content and then
257 # wrap it appropriately.
258 cmd = put_cmd_in_ert(cmd)
259 retval += "\n" + cmd + "\n"
261 m = labelre.match(line)
262 # put all remaining braces in ERT
263 line = wrap_into_ert(line, '}', '}')
264 line = wrap_into_ert(line, '{', '{')
266 # active character that is not available in all font encodings
267 line = wrap_into_ert(line, '|', '|')
272 unicode_reps = read_unicodesymbols()
275 #Might should do latex2ert first, then deal with stuff that DOESN'T
276 #end up inside ERT. That routine could be modified so that it returned
277 #a list of lines, and we could then skip ERT bits and only deal with
279 def latex2lyx(data, isindex):
280 '''Takes a string, possibly multi-line, and returns the result of
281 converting LaTeX constructs into LyX constructs. Returns a list of
282 lines, suitable for insertion into document.body.
283 The bool isindex specifies whether we are in an index macro (which
284 has some specific active characters that need to be ERTed).'''
290 # Convert LaTeX to Unicode
291 # Commands of this sort need to be checked to make sure they are
292 # followed by a non-alpha character, lest we replace too much.
293 hardone = re.compile(r'^\\\\[a-zA-Z]+$')
295 for rep in unicode_reps:
296 if hardone.match(rep[0]):
299 pos = data.find(rep[0], pos)
302 nextpos = pos + len(rep[0])
303 if nextpos < len(data) and data[nextpos].isalpha():
304 # not the end of that command
307 data = data[:pos] + rep[1] + data[nextpos:]
310 data = data.replace(rep[0], rep[1])
314 data = wrap_into_ert(data, r'\"', '"')
316 data = data.replace('\\\\', '\\')
319 mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
320 lines = data.split('\n')
322 #document.warning("LINE: " + line)
323 #document.warning(str(i) + ":" + document.body[i])
324 #document.warning("LAST: " + document.body[-1])
329 f = m.group(2).replace('\\\\', '\\')
333 s = latex2ert(s, isindex)
334 subst = s.split('\n')
336 retval.append("\\begin_inset Formula " + f)
337 retval.append("\\end_inset")
339 # Handle whatever is left, which is just text
340 g = latex2ert(g, isindex)
341 subst = g.split('\n')
346 def lyxline2latex(document, line, inert):
347 'Convert some LyX stuff into corresponding LaTeX stuff line-wise, as best we can.'
348 if line.startswith("\\begin_inset Formula"):
350 elif line.startswith("\\begin_inset Quotes"):
351 # For now, we do a very basic reversion. Someone who understands
352 # quotes is welcome to fix it up.
353 qtype = line[20:].strip()
367 elif line.isspace() or \
368 line.startswith("\\begin_layout") or \
369 line.startswith("\\end_layout") or \
370 line.startswith("\\begin_inset") or \
371 line.startswith("\\end_inset") or \
372 line.startswith("\\lang") or \
373 line.strip() == "status collapsed" or \
374 line.strip() == "status open":
378 # this needs to be added to the preamble because of cases like
379 # \textmu, \textbackslash, etc.
380 add_to_preamble(document, ['% added by lyx2lyx for converted entries',
381 '\\@ifundefined{textmu}',
382 ' {\\usepackage{textcomp}}{}'])
383 # a lossless reversion is not possible
384 # try at least to handle some common insets and settings
386 line = line.replace(r'\backslash', '\\')
388 line = line.replace('&', '\\&{}')
389 line = line.replace('#', '\\#{}')
390 line = line.replace('^', '\\^{}')
391 line = line.replace('%', '\\%{}')
392 line = line.replace('_', '\\_{}')
393 line = line.replace('$', '\\${}')
395 # Do the LyX text --> LaTeX conversion
396 for rep in unicode_reps:
397 line = line.replace(rep[1], rep[0].replace('\\\\', '\\') + "{}")
398 line = line.replace(r'\backslash', r'\textbackslash{}')
399 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
400 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
401 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
402 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
403 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
404 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
405 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
406 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
407 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
411 def lyx2latex(document, lines):
412 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
413 # clean up multiline stuff
417 for curline in range(len(lines)):
418 line = lines[curline]
419 if line.startswith("\\begin_inset ERT"):
420 # We don't want to replace things inside ERT, so figure out
421 # where the end of the inset is.
422 ert_end = find_end_of_inset(lines, curline + 1)
424 inert = ert_end >= curline
425 content += lyxline2latex(document, lines[curline], inert)
430 ####################################################################
432 def convert_ltcaption(document):
435 i = find_token(document.body, "\\begin_inset Tabular", i)
438 j = find_end_of_inset(document.body, i + 1)
440 document.warning("Malformed LyX document: Could not find end of tabular.")
444 nrows = int(document.body[i+1].split('"')[3])
445 ncols = int(document.body[i+1].split('"')[5])
448 for k in range(nrows):
449 m = find_token(document.body, "<row", m)
452 for k in range(ncols):
453 m = find_token(document.body, "<cell", m)
455 mend = find_token(document.body, "</cell>", m + 1)
456 # first look for caption insets
457 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
458 # then look for ERT captions
460 mcap = find_token(document.body, "caption", m + 1, mend)
462 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
465 if caption == 'true':
467 set_option(document, r, 'caption', 'true')
468 set_option(document, m, 'multicolumn', '1')
469 set_option(document, m, 'bottomline', 'false')
470 set_option(document, m, 'topline', 'false')
471 set_option(document, m, 'rightline', 'false')
472 set_option(document, m, 'leftline', 'false')
473 #j = find_end_of_inset(document.body, j + 1)
475 set_option(document, m, 'multicolumn', '2')
482 #FIXME Use of wrap_into_ert can confuse lyx2lyx
483 def revert_ltcaption(document):
486 i = find_token(document.body, "\\begin_inset Tabular", i)
489 j = find_end_of_inset(document.body, i + 1)
491 document.warning("Malformed LyX document: Could not find end of tabular.")
496 nrows = int(document.body[i+1].split('"')[3])
497 ncols = int(document.body[i+1].split('"')[5])
499 for k in range(nrows):
500 m = find_token(document.body, "<row", m)
501 caption = get_option(document, m, 'caption', 'false')
502 if caption == 'true':
503 remove_option(document, m, 'caption')
504 for k in range(ncols):
505 m = find_token(document.body, "<cell", m)
506 remove_option(document, m, 'multicolumn')
508 m = find_token(document.body, "\\begin_inset Caption", m)
511 m = find_end_of_inset(document.body, m + 1)
512 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
518 def convert_tablines(document):
521 i = find_token(document.body, "\\begin_inset Tabular", i)
523 # LyX 1.3 inserted an extra space between \begin_inset
524 # and Tabular so let us try if this is the case and fix it.
525 i = find_token(document.body, "\\begin_inset Tabular", i)
529 document.body[i] = "\\begin_inset Tabular"
530 j = find_end_of_inset(document.body, i + 1)
532 document.warning("Malformed LyX document: Could not find end of tabular.")
537 nrows = int(document.body[i+1].split('"')[3])
538 ncols = int(document.body[i+1].split('"')[5])
541 for k in range(ncols):
542 m = find_token(document.body, "<column", m)
543 left = get_option(document, m, 'leftline', 'false')
544 right = get_option(document, m, 'rightline', 'false')
545 col_info.append([left, right])
546 remove_option(document, m, 'leftline')
547 remove_option(document, m, 'rightline')
551 for k in range(nrows):
552 m = find_token(document.body, "<row", m)
553 top = get_option(document, m, 'topline', 'false')
554 bottom = get_option(document, m, 'bottomline', 'false')
555 row_info.append([top, bottom])
556 remove_option(document, m, 'topline')
557 remove_option(document, m, 'bottomline')
562 for k in range(nrows*ncols):
563 m = find_token(document.body, "<cell", m)
564 mc_info.append(get_option(document, m, 'multicolumn', '0'))
567 for l in range(nrows):
568 for k in range(ncols):
569 m = find_token(document.body, '<cell', m)
570 if mc_info[l*ncols + k] == '0':
571 r = set_option(document, m, 'topline', row_info[l][0])
572 r = set_option(document, m, 'bottomline', row_info[l][1])
573 r = set_option(document, m, 'leftline', col_info[k][0])
574 r = set_option(document, m, 'rightline', col_info[k][1])
575 elif mc_info[l*ncols + k] == '1':
577 while s < ncols and mc_info[l*ncols + s] == '2':
579 if s < ncols and mc_info[l*ncols + s] != '1':
580 r = set_option(document, m, 'rightline', col_info[k][1])
581 if k > 0 and mc_info[l*ncols + k - 1] == '0':
582 r = set_option(document, m, 'leftline', col_info[k][0])
587 def revert_tablines(document):
590 i = find_token(document.body, "\\begin_inset Tabular", i)
593 j = find_end_of_inset(document.body, i)
595 document.warning("Malformed LyX document: Could not find end of tabular.")
600 nrows = int(document.body[i+1].split('"')[3])
601 ncols = int(document.body[i+1].split('"')[5])
604 for k in range(nrows*ncols):
605 m = find_token(document.body, "<cell", m)
606 top = get_option(document, m, 'topline', 'false')
607 bottom = get_option(document, m, 'bottomline', 'false')
608 left = get_option(document, m, 'leftline', 'false')
609 right = get_option(document, m, 'rightline', 'false')
610 lines.append([top, bottom, left, right])
613 # we will want to ignore longtable captions
616 for k in range(nrows):
617 m = find_token(document.body, "<row", m)
618 caption = get_option(document, m, 'caption', 'false')
619 caption_info.append([caption])
624 for k in range(ncols):
625 m = find_token(document.body, "<column", m)
627 for l in range(nrows):
628 left = lines[l*ncols + k][2]
629 if left == 'false' and caption_info[l] == 'false':
631 set_option(document, m, 'leftline', left)
633 for l in range(nrows):
634 right = lines[l*ncols + k][3]
635 if right == 'false' and caption_info[l] == 'false':
637 set_option(document, m, 'rightline', right)
641 for k in range(nrows):
642 m = find_token(document.body, "<row", m)
644 for l in range(ncols):
645 top = lines[k*ncols + l][0]
648 if caption_info[k] == 'false':
650 set_option(document, m, 'topline', top)
652 for l in range(ncols):
653 bottom = lines[k*ncols + l][1]
654 if bottom == 'false':
656 if caption_info[k] == 'false':
658 set_option(document, m, 'bottomline', bottom)
664 def fix_wrong_tables(document):
667 i = find_token(document.body, "\\begin_inset Tabular", i)
670 j = find_end_of_inset(document.body, i + 1)
672 document.warning("Malformed LyX document: Could not find end of tabular.")
677 nrows = int(document.body[i+1].split('"')[3])
678 ncols = int(document.body[i+1].split('"')[5])
680 for l in range(nrows):
682 for k in range(ncols):
683 m = find_token(document.body, '<cell', m)
685 if document.body[m].find('multicolumn') != -1:
686 multicol_cont = int(document.body[m].split('"')[1])
688 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
689 document.body[m] = document.body[m][:5] + document.body[m][21:]
692 prev_multicolumn = multicol_cont
699 def close_begin_deeper(document):
703 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
708 if document.body[i][:13] == "\\begin_deeper":
715 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
718 def long_charstyle_names(document):
721 i = find_token(document.body, "\\begin_inset CharStyle", i)
724 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
727 def revert_long_charstyle_names(document):
730 i = find_token(document.body, "\\begin_inset CharStyle", i)
733 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
737 def axe_show_label(document):
740 i = find_token(document.body, "\\begin_inset CharStyle", i)
743 if document.body[i + 1].find("show_label") != -1:
744 if document.body[i + 1].find("true") != -1:
745 document.body[i + 1] = "status open"
746 del document.body[ i + 2]
748 if document.body[i + 1].find("false") != -1:
749 document.body[i + 1] = "status collapsed"
750 del document.body[ i + 2]
752 document.warning("Malformed LyX document: show_label neither false nor true.")
754 document.warning("Malformed LyX document: show_label missing in CharStyle.")
759 def revert_show_label(document):
762 i = find_token(document.body, "\\begin_inset CharStyle", i)
765 if document.body[i + 1].find("status open") != -1:
766 document.body.insert(i + 1, "show_label true")
768 if document.body[i + 1].find("status collapsed") != -1:
769 document.body.insert(i + 1, "show_label false")
771 document.warning("Malformed LyX document: no legal status line in CharStyle.")
774 def revert_begin_modules(document):
777 i = find_token(document.header, "\\begin_modules", i)
780 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
782 # this should not happen
784 document.header[i : j + 1] = []
786 def convert_flex(document):
787 "Convert CharStyle to Flex"
790 i = find_token(document.body, "\\begin_inset CharStyle", i)
793 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
795 def revert_flex(document):
796 "Revert Flex to CharStyle"
799 i = find_token(document.body, "\\begin_inset Flex", i)
802 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
805 def revert_pdf_options(document):
806 "Revert PDF options for hyperref."
807 # store the PDF options and delete the entries from the Lyx file
815 bookmarksnumbered = ""
817 bookmarksopenlevel = ""
825 i = find_token(document.header, "\\use_hyperref", i)
827 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
828 del document.header[i]
829 i = find_token(document.header, "\\pdf_store_options", i)
831 del document.header[i]
832 i = find_token(document.header, "\\pdf_title", 0)
834 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
835 title = ' pdftitle={' + title + '}'
836 del document.header[i]
837 i = find_token(document.header, "\\pdf_author", 0)
839 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
841 author = ' pdfauthor={' + author + '}'
843 author = ',\n pdfauthor={' + author + '}'
844 del document.header[i]
845 i = find_token(document.header, "\\pdf_subject", 0)
847 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
848 if title == "" and author == "":
849 subject = ' pdfsubject={' + subject + '}'
851 subject = ',\n pdfsubject={' + subject + '}'
852 del document.header[i]
853 i = find_token(document.header, "\\pdf_keywords", 0)
855 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
856 if title == "" and author == "" and subject == "":
857 keywords = ' pdfkeywords={' + keywords + '}'
859 keywords = ',\n pdfkeywords={' + keywords + '}'
860 del document.header[i]
861 i = find_token(document.header, "\\pdf_bookmarks", 0)
863 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
864 bookmarks = ',\n bookmarks=' + bookmarks
865 del document.header[i]
866 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
868 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
869 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
870 del document.header[i]
871 i = find_token(document.header, "\\pdf_bookmarksopen", i)
873 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
874 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
875 del document.header[i]
876 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
878 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
879 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
880 del document.header[i]
881 i = find_token(document.header, "\\pdf_breaklinks", i)
883 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
884 breaklinks = ',\n breaklinks=' + breaklinks
885 del document.header[i]
886 i = find_token(document.header, "\\pdf_pdfborder", i)
888 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
889 if pdfborder == 'true':
890 pdfborder = ',\n pdfborder={0 0 0}'
892 pdfborder = ',\n pdfborder={0 0 1}'
893 del document.header[i]
894 i = find_token(document.header, "\\pdf_colorlinks", i)
896 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
897 colorlinks = ',\n colorlinks=' + colorlinks
898 del document.header[i]
899 i = find_token(document.header, "\\pdf_backref", i)
901 backref = get_value_string(document.header, '\\pdf_backref', 0)
902 backref = ',\n backref=' + backref
903 del document.header[i]
904 i = find_token(document.header, "\\pdf_pagebackref", i)
906 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
907 pagebackref = ',\n pagebackref=' + pagebackref
908 del document.header[i]
909 i = find_token(document.header, "\\pdf_pagemode", 0)
911 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
912 pagemode = ',\n pdfpagemode=' + pagemode
913 del document.header[i]
914 i = find_token(document.header, "\\pdf_quoted_options", 0)
916 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
917 if title == "" and author == "" and subject == "" and keywords == "":
918 otheroptions = ' ' + otheroptions
920 otheroptions = ',\n ' + otheroptions
921 del document.header[i]
923 # write to the preamble when hyperref was used
925 # preamble write preparations
926 # bookmark numbers are only output when they are turned on
927 if bookmarksopen == ',\n bookmarksopen=true':
928 bookmarksopen = bookmarksopen + bookmarksopenlevel
929 if bookmarks == ',\n bookmarks=true':
930 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
932 bookmarks = bookmarks
933 # hypersetup is only output when there are things to be set up
934 setupstart = '\\hypersetup{%\n'
936 if otheroptions == "" and title == "" and author == ""\
937 and subject == "" and keywords == "":
941 # babel must be loaded before hyperref and hyperref the first part
942 # of the preamble, like in LyX 1.6
943 insert_to_preamble(0, document,
944 '% Commands inserted by lyx2lyx for PDF properties\n'
945 + '\\usepackage{babel}\n'
946 + '\\usepackage[unicode=true'
965 def remove_inzip_options(document):
966 "Remove inzipName and embed options from the Graphics inset"
969 i = find_token(document.body, "\\begin_inset Graphics", i)
972 j = find_end_of_inset(document.body, i + 1)
975 document.warning("Malformed LyX document: Could not find end of graphics inset.")
978 # If there's a inzip param, just remove that
979 k = find_token(document.body, "\tinzipName", i + 1, j)
982 # embed option must follow the inzipName option
983 del document.body[k+1]
987 def convert_inset_command(document):
990 \begin_inset LatexCommand cmd
992 \begin_inset CommandInset InsetType
997 i = find_token(document.body, "\\begin_inset LatexCommand", i)
1000 line = document.body[i]
1001 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
1003 cmdName = m.group(1)
1005 #this is adapted from factory.cpp
1006 if cmdName[0:4].lower() == "cite":
1007 insetName = "citation"
1008 elif cmdName == "url" or cmdName == "htmlurl":
1010 elif cmdName[-3:] == "ref":
1012 elif cmdName == "tableofcontents":
1014 elif cmdName == "printnomenclature":
1015 insetName = "nomencl_print"
1016 elif cmdName == "printindex":
1017 insetName = "index_print"
1020 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
1021 document.body[i : i+1] = insertion
1024 def revert_inset_command(document):
1027 \begin_inset CommandInset InsetType
1030 \begin_inset LatexCommand cmd
1031 Some insets may end up being converted to insets earlier versions of LyX
1032 will not be able to recognize. Not sure what to do about that.
1036 i = find_token(document.body, "\\begin_inset CommandInset", i)
1039 nextline = document.body[i+1]
1040 r = re.compile(r'LatexCommand\s+(.*)$')
1041 m = r.match(nextline)
1043 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
1046 cmdName = m.group(1)
1047 insertion = ["\\begin_inset LatexCommand " + cmdName]
1048 document.body[i : i+2] = insertion
1051 def convert_wrapfig_options(document):
1052 "Convert optional options for wrap floats (wrapfig)."
1053 # adds the tokens "lines", "placement", and "overhang"
1056 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1059 document.body.insert(i + 1, "lines 0")
1060 j = find_token(document.body, "placement", i)
1061 # placement can be already set or not; if not, set it
1063 document.body.insert(i + 3, "overhang 0col%")
1065 document.body.insert(i + 2, "placement o")
1066 document.body.insert(i + 3, "overhang 0col%")
1070 def revert_wrapfig_options(document):
1071 "Revert optional options for wrap floats (wrapfig)."
1074 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1077 j = find_end_of_inset(document.body, i)
1079 document.warning("Can't find end of Wrap inset at line " + str(i))
1082 k = find_default_layout(document, i, j)
1084 document.warning("Can't find default layout for Wrap figure!")
1087 # Options should be between i and k now
1088 l = find_token(document.body, "lines", i, k)
1090 document.warning("Can't find lines option for Wrap figure!")
1093 m = find_token(document.body, "overhang", i + 1, k)
1095 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1098 # Do these in reverse order
1099 del document.body[m]
1100 del document.body[l]
1104 def convert_latexcommand_index(document):
1105 "Convert from LatexCommand form to collapsable form."
1107 r1 = re.compile('name "(.*)"')
1109 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1112 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1115 j = find_end_of_inset(document.body, i + 1)
1117 document.warning("Unable to find end of index inset at line " + str(i) + "!")
1120 m = r1.match(document.body[i + 2])
1122 document.warning("Unable to match: " + document.body[i+2])
1123 # this can happen with empty index insets!
1126 fullcontent = m.group(1)
1127 linelist = latex2lyx(fullcontent, True)
1128 #document.warning(fullcontent)
1130 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1131 linelist + ["\\end_layout"]
1132 document.body[i : j] = linelist
1133 i += len(linelist) - (j - i)
1136 def revert_latexcommand_index(document):
1137 "Revert from collapsable form to LatexCommand form."
1140 i = find_token(document.body, "\\begin_inset Index", i)
1143 j = find_end_of_inset(document.body, i + 1)
1147 content = lyx2latex(document, document.body[i:j])
1149 content = content.replace('"', r'\"')
1150 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1151 "name " + '"' + content + '"', ""]
1155 def revert_wraptable(document):
1156 "Revert wrap table to wrap figure."
1159 i = find_token(document.body, "\\begin_inset Wrap table", i)
1162 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1166 def revert_vietnamese(document):
1167 "Set language Vietnamese to English"
1168 # Set document language from Vietnamese to English
1170 if document.language == "vietnamese":
1171 document.language = "english"
1172 i = find_token(document.header, "\\language", 0)
1174 document.header[i] = "\\language english"
1177 j = find_token(document.body, "\\lang vietnamese", j)
1180 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1184 def convert_japanese_cjk(document):
1185 "Set language japanese to japanese-cjk"
1186 # Set document language from japanese-plain to japanese
1188 if document.language == "japanese":
1189 document.language = "japanese-cjk"
1190 i = find_token(document.header, "\\language", 0)
1192 document.header[i] = "\\language japanese-cjk"
1195 j = find_token(document.body, "\\lang japanese", j)
1198 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1202 def revert_japanese(document):
1203 "Set language japanese-plain to japanese"
1204 # Set document language from japanese-plain to japanese
1206 if document.language == "japanese-plain":
1207 document.language = "japanese"
1208 i = find_token(document.header, "\\language", 0)
1210 document.header[i] = "\\language japanese"
1213 j = find_token(document.body, "\\lang japanese-plain", j)
1216 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1220 def revert_japanese_cjk(document):
1221 "Set language japanese-cjk to japanese"
1222 # Set document language from japanese-plain to japanese
1224 if document.language == "japanese-cjk":
1225 document.language = "japanese"
1226 i = find_token(document.header, "\\language", 0)
1228 document.header[i] = "\\language japanese"
1231 j = find_token(document.body, "\\lang japanese-cjk", j)
1234 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1238 def revert_japanese_encoding(document):
1239 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1240 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1242 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1244 document.header[i] = "\\inputencoding EUC-JP"
1246 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1248 document.header[j] = "\\inputencoding JIS"
1250 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1251 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1252 document.header[k] = "\\inputencoding UTF8"
1255 def revert_inset_info(document):
1256 'Replace info inset with its content'
1259 i = find_token(document.body, '\\begin_inset Info', i)
1262 j = find_end_of_inset(document.body, i + 1)
1265 document.warning("Malformed LyX document: Could not find end of Info inset.")
1270 for k in range(i, j+1):
1271 if document.body[k].startswith("arg"):
1272 arg = document.body[k][3:].strip()
1273 # remove embracing quotation marks
1276 if arg[len(arg) - 1] == '"':
1277 arg = arg[:len(arg) - 1]
1278 # \" to straight quote
1279 arg = arg.replace(r'\"', '"')
1281 arg = arg.replace(r'\\', "\\backslash\n")
1282 if document.body[k].startswith("type"):
1283 type = document.body[k][4:].strip().strip('"')
1284 # I think there is a newline after \\end_inset, which should be removed.
1285 if document.body[j + 1].strip() == "":
1286 document.body[i : (j + 2)] = [type + ':' + arg]
1288 document.body[i : (j + 1)] = [type + ':' + arg]
1291 def convert_pdf_options(document):
1292 # Set the pdfusetitle tag, delete the pdf_store_options,
1293 # set quotes for bookmarksopenlevel"
1294 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1296 k = find_token(document.header, "\\use_hyperref", 0)
1297 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1298 k = find_token(document.header, "\\pdf_store_options", 0)
1300 del document.header[k]
1301 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1303 document.header[i] = document.header[i].replace('"', '')
1306 def revert_pdf_options_2(document):
1307 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1308 k = find_token(document.header, "\\use_hyperref", 0)
1309 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1311 del document.header[i]
1312 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1314 values = document.header[i].split()
1315 values[1] = ' "' + values[1] + '"'
1316 document.header[i] = ''.join(values)
1319 def convert_htmlurl(document):
1320 'Convert "htmlurl" to "href" insets for docbook'
1321 if document.backend != "docbook":
1325 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1328 document.body[i] = "\\begin_inset CommandInset href"
1329 document.body[i + 1] = "LatexCommand href"
1333 def convert_url(document):
1334 'Convert url insets to url charstyles'
1335 if document.backend == "docbook":
1339 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1342 n = find_token(document.body, "name", i)
1344 # place the URL name in typewriter before the new URL insert
1345 # grab the name 'bla' from the e.g. the line 'name "bla"',
1346 # therefore start with the 6th character
1347 name = document.body[n][6:-1]
1348 newname = [name + " "]
1349 document.body[i:i] = newname
1351 j = find_token(document.body, "target", i)
1353 document.warning("Malformed LyX document: Can't find target for url inset")
1356 target = document.body[j][8:-1]
1357 k = find_token(document.body, "\\end_inset", j)
1359 document.warning("Malformed LyX document: Can't find end of url inset")
1362 newstuff = ["\\begin_inset Flex URL",
1363 "status collapsed", "",
1364 "\\begin_layout Standard",
1369 document.body[i:k] = newstuff
1370 i = i + len(newstuff)
1372 def convert_ams_classes(document):
1373 tc = document.textclass
1374 if (tc != "amsart" and tc != "amsart-plain" and
1375 tc != "amsart-seq" and tc != "amsbook"):
1377 if tc == "amsart-plain":
1378 document.textclass = "amsart"
1379 document.set_textclass()
1380 document.add_module("Theorems (Starred)")
1382 if tc == "amsart-seq":
1383 document.textclass = "amsart"
1384 document.set_textclass()
1385 document.add_module("Theorems (AMS)")
1387 #Now we want to see if any of the environments in the extended theorems
1388 #module were used in this document. If so, we'll add that module, too.
1389 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1390 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1393 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1396 i = find_token(document.body, "\\begin_layout", i)
1399 m = r.match(document.body[i])
1401 # This is an empty layout
1402 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1406 if layouts.count(m) != 0:
1407 document.add_module("Theorems (AMS-Extended)")
1411 def revert_href(document):
1412 'Reverts hyperlink insets (href) to url insets (url)'
1415 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1418 document.body[i : i + 2] = \
1419 ["\\begin_inset CommandInset url", "LatexCommand url"]
1422 def revert_url(document):
1423 'Reverts Flex URL insets to old-style URL insets'
1426 i = find_token(document.body, "\\begin_inset Flex URL", i)
1429 j = find_end_of_inset(document.body, i)
1431 document.warning("Can't find end of inset in revert_url!")
1433 k = find_default_layout(document, i, j)
1435 document.warning("Can't find default layout in revert_url!")
1438 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1439 if l == -1 or l >= j:
1440 document.warning("Can't find end of default layout in revert_url!")
1443 # OK, so the inset's data is between lines k and l.
1444 data = " ".join(document.body[k+1:l])
1446 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1448 document.body[i:j+1] = newinset
1449 i = i + len(newinset)
1452 def convert_include(document):
1453 'Converts include insets to new format.'
1455 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1457 i = find_token(document.body, "\\begin_inset Include", i)
1460 line = document.body[i]
1461 previewline = document.body[i + 1]
1464 document.warning("Unable to match line " + str(i) + " of body!")
1470 insertion = ["\\begin_inset CommandInset include",
1471 "LatexCommand " + cmd, previewline,
1472 "filename \"" + fn + "\""]
1475 insertion.append("lstparams " + '"' + opt + '"')
1477 document.body[i : i + 2] = insertion
1481 def revert_include(document):
1482 'Reverts include insets to old format.'
1484 r0 = re.compile('preview.*')
1485 r1 = re.compile('LatexCommand (.+)')
1486 r2 = re.compile('filename "(.+)"')
1487 r3 = re.compile('lstparams "(.*)"')
1489 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1493 m = r1.match(document.body[nextline])
1495 document.warning("Malformed LyX document: No LatexCommand line for `" +
1496 document.body[i] + "' on line " + str(i) + ".")
1501 if r0.match(document.body[nextline]):
1502 previewline = document.body[nextline]
1506 m = r2.match(document.body[nextline])
1508 document.warning("Malformed LyX document: No filename line for `" + \
1509 document.body[i] + "' on line " + str(i) + ".")
1515 if (cmd == "lstinputlisting"):
1516 m = r3.match(document.body[nextline])
1518 options = m.group(1)
1521 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1523 newline += ("[" + options + "]")
1524 insertion = [newline]
1525 if previewline != "":
1526 insertion.append(previewline)
1527 document.body[i : nextline] = insertion
1531 def revert_albanian(document):
1532 "Set language Albanian to English"
1534 if document.language == "albanian":
1535 document.language = "english"
1536 i = find_token(document.header, "\\language", 0)
1538 document.header[i] = "\\language english"
1541 j = find_token(document.body, "\\lang albanian", j)
1544 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1548 def revert_lowersorbian(document):
1549 "Set language lower Sorbian to English"
1551 if document.language == "lowersorbian":
1552 document.language = "english"
1553 i = find_token(document.header, "\\language", 0)
1555 document.header[i] = "\\language english"
1558 j = find_token(document.body, "\\lang lowersorbian", j)
1561 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1565 def revert_uppersorbian(document):
1566 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1568 if document.language == "uppersorbian":
1569 document.language = "usorbian"
1570 i = find_token(document.header, "\\language", 0)
1572 document.header[i] = "\\language usorbian"
1575 j = find_token(document.body, "\\lang uppersorbian", j)
1578 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1582 def convert_usorbian(document):
1583 "Set language usorbian to uppersorbian"
1585 if document.language == "usorbian":
1586 document.language = "uppersorbian"
1587 i = find_token(document.header, "\\language", 0)
1589 document.header[i] = "\\language uppersorbian"
1592 j = find_token(document.body, "\\lang usorbian", j)
1595 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1599 def convert_macro_global(document):
1600 "Remove TeX code command \global when it is in front of a macro"
1601 # math macros are nowadays already defined \global, so that an additional
1602 # \global would make the document uncompilable, see
1603 # http://www.lyx.org/trac/ticket/5371
1604 # We're looking for something like this:
1608 # \begin_layout Plain Layout
1618 # \begin_inset FormulaMacro
1619 # \renewcommand{\foo}{123}
1623 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1626 # if i <= 13, then there isn't enough room for the ERT
1630 if document.body[i-6] == "global":
1631 del document.body[i-13 : i]
1637 def revert_macro_optional_params(document):
1638 "Convert macro definitions with optional parameters into ERTs"
1639 # Stub to convert macro definitions with one or more optional parameters
1640 # into uninterpreted ERT insets
1643 def revert_hyperlinktype(document):
1644 'Reverts hyperlink type'
1648 i = find_token(document.body, "target", i)
1651 j = find_token(document.body, "type", i)
1655 del document.body[j]
1659 def revert_pagebreak(document):
1660 'Reverts pagebreak to ERT'
1663 i = find_token(document.body, "\\pagebreak", i)
1666 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1667 '\\begin_layout Standard\n\n\n\\backslash\n' \
1668 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1672 def revert_linebreak(document):
1673 'Reverts linebreak to ERT'
1676 i = find_token(document.body, "\\linebreak", i)
1679 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1680 '\\begin_layout Standard\n\n\n\\backslash\n' \
1681 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1685 def revert_latin(document):
1686 "Set language Latin to English"
1688 if document.language == "latin":
1689 document.language = "english"
1690 i = find_token(document.header, "\\language", 0)
1692 document.header[i] = "\\language english"
1695 j = find_token(document.body, "\\lang latin", j)
1698 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1702 def revert_samin(document):
1703 "Set language North Sami to English"
1705 if document.language == "samin":
1706 document.language = "english"
1707 i = find_token(document.header, "\\language", 0)
1709 document.header[i] = "\\language english"
1712 j = find_token(document.body, "\\lang samin", j)
1715 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1719 def convert_serbocroatian(document):
1720 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1722 if document.language == "serbocroatian":
1723 document.language = "croatian"
1724 i = find_token(document.header, "\\language", 0)
1726 document.header[i] = "\\language croatian"
1729 j = find_token(document.body, "\\lang serbocroatian", j)
1732 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1736 def convert_framed_notes(document):
1737 "Convert framed notes to boxes. "
1740 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1743 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1752 'height_special "totalheight"']
1753 document.body[i:i+1] = subst
1757 def convert_module_names(document):
1758 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1759 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1760 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1761 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1762 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1763 modlist = document.get_module_list()
1764 if len(modlist) == 0:
1768 if modulemap.has_key(mod):
1769 newmodlist.append(modulemap[mod])
1771 document.warning("Can't find module %s in the module map!" % mod)
1772 newmodlist.append(mod)
1773 document.set_module_list(newmodlist)
1776 def revert_module_names(document):
1777 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1778 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1779 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1780 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1781 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1782 modlist = document.get_module_list()
1783 if len(modlist) == 0:
1787 if mod in modulemap:
1788 newmodlist.append(modulemap[mod])
1790 document.warning("Can't find module %s in the module map!" % mod)
1791 newmodlist.append(mod)
1792 document.set_module_list(newmodlist)
1795 def revert_colsep(document):
1796 i = find_token(document.header, "\\columnsep", 0)
1799 colsepline = document.header[i]
1800 r = re.compile(r'\\columnsep (.*)')
1801 m = r.match(colsepline)
1803 document.warning("Malformed column separation line!")
1806 del document.header[i]
1807 #it seems to be safe to add the package even if it is already used
1808 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1810 add_to_preamble(document, pretext)
1813 def revert_framed_notes(document):
1814 "Revert framed boxes to notes. "
1817 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1821 j = find_end_of_inset(document.body, i + 1)
1824 document.warning("Malformed LyX document: Could not find end of Box inset.")
1827 k = find_token(document.body, "status", i + 1, j)
1829 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1832 status = document.body[k]
1833 l = find_default_layout(document, i + 1, j)
1835 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1838 m = find_token(document.body, "\\end_layout", i + 1, j)
1840 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1843 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1844 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1845 if ibox == -1 and pbox == -1:
1846 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1847 del document.body[i+1:k]
1849 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1850 subst1 = [document.body[l],
1851 "\\begin_inset Note Shaded",
1853 '\\begin_layout Standard']
1854 document.body[l:l + 1] = subst1
1855 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1856 document.body[m:m + 1] = subst2
1860 def revert_slash(document):
1861 'Revert \\SpecialChar \\slash{} to ERT'
1863 while i < len(document.body):
1864 m = re.match(r'(.*)\\SpecialChar \\slash{}(.*)', document.body[i])
1869 '\\begin_inset ERT',
1870 'status collapsed', '',
1871 '\\begin_layout Standard',
1872 '', '', '\\backslash',
1877 document.body[i: i+1] = subst
1883 def revert_nobreakdash(document):
1884 'Revert \\SpecialChar \\nobreakdash- to ERT'
1886 while i < len(document.body):
1887 m = re.match(r'(.*)\\SpecialChar \\nobreakdash-(.*)', document.body[i])
1892 '\\begin_inset ERT',
1893 'status collapsed', '',
1894 '\\begin_layout Standard', '', '',
1900 document.body[i: i+1] = subst
1902 j = find_token(document.header, "\\use_amsmath", 0)
1904 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1907 document.header[j] = "\\use_amsmath 2"
1912 #Returns number of lines added/removed
1913 def revert_nocite_key(body, start, end):
1914 'key "..." -> \nocite{...}'
1915 r = re.compile(r'^key "(.*)"')
1919 m = r.match(body[i])
1921 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1922 j += 1 # because we added a line
1923 i += 2 # skip that line
1926 j -= 1 # because we deleted a line
1927 # no need to change i, since it now points to the next line
1931 def revert_nocite(document):
1932 "Revert LatexCommand nocite to ERT"
1935 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1938 if (document.body[i+1] != "LatexCommand nocite"):
1939 # note that we already incremented i
1942 insetEnd = find_end_of_inset(document.body, i)
1944 #this should not happen
1945 document.warning("End of CommandInset citation not found in revert_nocite!")
1948 paramLocation = i + 2 #start of the inset's parameters
1950 document.body[i:i+2] = \
1951 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1952 # that added two lines
1955 #print insetEnd, document.body[i: insetEnd + 1]
1956 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1957 #print insetEnd, document.body[i: insetEnd + 1]
1958 document.body.insert(insetEnd, "\\end_layout")
1959 document.body.insert(insetEnd + 1, "")
1963 def revert_btprintall(document):
1964 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1965 i = find_token(document.header, '\\use_bibtopic', 0)
1967 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1969 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1971 while i < len(document.body):
1972 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1975 j = find_end_of_inset(document.body, i + 1)
1977 #this should not happen
1978 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1979 j = len(document.body)
1980 # this range isn't really right, but it should be OK, since we shouldn't
1981 # see more than one matching line in each inset
1983 for k in range(i, j):
1984 if (document.body[k] == 'btprint "btPrintAll"'):
1985 del document.body[k]
1986 subst = ["\\begin_inset ERT",
1987 "status collapsed", "",
1988 "\\begin_layout Standard", "",
1993 document.body[i:i] = subst
1994 addlines = addedlines + len(subst) - 1
1998 def revert_bahasam(document):
1999 "Set language Bahasa Malaysia to Bahasa Indonesia"
2001 if document.language == "bahasam":
2002 document.language = "bahasa"
2003 i = find_token(document.header, "\\language", 0)
2005 document.header[i] = "\\language bahasa"
2008 j = find_token(document.body, "\\lang bahasam", j)
2011 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
2015 def revert_interlingua(document):
2016 "Set language Interlingua to English"
2018 if document.language == "interlingua":
2019 document.language = "english"
2020 i = find_token(document.header, "\\language", 0)
2022 document.header[i] = "\\language english"
2025 j = find_token(document.body, "\\lang interlingua", j)
2028 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
2032 def revert_serbianlatin(document):
2033 "Set language Serbian-Latin to Croatian"
2035 if document.language == "serbian-latin":
2036 document.language = "croatian"
2037 i = find_token(document.header, "\\language", 0)
2039 document.header[i] = "\\language croatian"
2042 j = find_token(document.body, "\\lang serbian-latin", j)
2045 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
2049 def revert_rotfloat(document):
2050 " Revert sideways custom floats. "
2053 # whitespace intended (exclude \\begin_inset FloatList)
2054 i = find_token(document.body, "\\begin_inset Float ", i)
2057 line = document.body[i]
2058 r = re.compile(r'\\begin_inset Float (.*)$')
2061 document.warning("Unable to match line " + str(i) + " of body!")
2064 floattype = m.group(1)
2065 if floattype == "figure" or floattype == "table":
2068 j = find_end_of_inset(document.body, i)
2070 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
2074 if get_value(document.body, 'sideways', i, j) == "false":
2077 l = find_default_layout(document, i + 1, j)
2079 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2082 subst = ['\\begin_layout Standard',
2083 '\\begin_inset ERT',
2084 'status collapsed', '',
2085 '\\begin_layout Standard', '', '',
2087 'end{sideways' + floattype + '}',
2088 '\\end_layout', '', '\\end_inset']
2089 document.body[j : j+1] = subst
2090 addedLines = len(subst) - 1
2091 del document.body[i+1 : l]
2092 addedLines -= (l-1) - (i+1)
2093 subst = ['\\begin_inset ERT', 'status collapsed', '',
2094 '\\begin_layout Standard', '', '', '\\backslash',
2095 'begin{sideways' + floattype + '}',
2096 '\\end_layout', '', '\\end_inset', '',
2098 document.body[i : i+1] = subst
2099 addedLines += len(subst) - 1
2100 if floattype == "algorithm":
2101 add_to_preamble(document,
2102 ['% Commands inserted by lyx2lyx for sideways algorithm float',
2103 '\\usepackage{rotfloat}',
2104 '\\floatstyle{ruled}',
2105 '\\newfloat{algorithm}{tbp}{loa}',
2106 '\\floatname{algorithm}{Algorithm}'])
2108 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
2112 def revert_widesideways(document):
2113 " Revert wide sideways floats. "
2116 # whitespace intended (exclude \\begin_inset FloatList)
2117 i = find_token(document.body, '\\begin_inset Float ', i)
2120 line = document.body[i]
2121 r = re.compile(r'\\begin_inset Float (.*)$')
2124 document.warning("Unable to match line " + str(i) + " of body!")
2127 floattype = m.group(1)
2128 if floattype != "figure" and floattype != "table":
2131 j = find_end_of_inset(document.body, i)
2133 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2136 if get_value(document.body, 'sideways', i, j) == "false" or \
2137 get_value(document.body, 'wide', i, j) == "false":
2140 l = find_default_layout(document, i + 1, j)
2142 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2145 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2146 'status collapsed', '',
2147 '\\begin_layout Standard', '', '', '\\backslash',
2148 'end{sideways' + floattype + '*}',
2149 '\\end_layout', '', '\\end_inset']
2150 document.body[j : j+1] = subst
2151 addedLines = len(subst) - 1
2152 del document.body[i+1:l-1]
2153 addedLines -= (l-1) - (i+1)
2154 subst = ['\\begin_inset ERT', 'status collapsed', '',
2155 '\\begin_layout Standard', '', '', '\\backslash',
2156 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2157 '\\end_inset', '', '\\end_layout', '']
2158 document.body[i : i+1] = subst
2159 addedLines += len(subst) - 1
2160 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2164 def revert_inset_embedding(document, type):
2165 ' Remove embed tag from certain type of insets'
2168 i = find_token(document.body, "\\begin_inset %s" % type, i)
2171 j = find_end_of_inset(document.body, i)
2173 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2176 k = find_token(document.body, "\tembed", i, j)
2178 k = find_token(document.body, "embed", i, j)
2180 del document.body[k]
2184 def revert_external_embedding(document):
2185 ' Remove embed tag from external inset '
2186 revert_inset_embedding(document, 'External')
2189 def convert_subfig(document):
2190 " Convert subfigures to subfloats. "
2194 i = find_token(document.body, '\\begin_inset Graphics', i)
2197 endInset = find_end_of_inset(document.body, i)
2199 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2202 k = find_token(document.body, '\tsubcaption', i, endInset)
2206 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2210 caption = document.body[l][16:].strip('"')
2211 del document.body[l]
2213 del document.body[k]
2215 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2216 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2217 '', '\\begin_layout Plain Layout'] + latex2lyx(caption, False) + \
2218 [ '\\end_layout', '', '\\end_inset', '',
2219 '\\end_layout', '', '\\begin_layout Plain Layout']
2220 document.body[i : i] = subst
2221 addedLines += len(subst)
2222 endInset += addedLines
2223 subst = ['', '\\end_inset', '', '\\end_layout']
2224 document.body[endInset : endInset] = subst
2225 addedLines += len(subst)
2229 def revert_subfig(document):
2230 " Revert subfloats. "
2233 # whitespace intended (exclude \\begin_inset FloatList)
2234 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2240 j = find_end_of_inset(document.body, i)
2242 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2243 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2245 continue # this will get us back to the outer loop, since j == -1
2246 # look for embedded float (= subfloat)
2247 # whitespace intended (exclude \\begin_inset FloatList)
2248 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2251 # is the subfloat aligned?
2252 al = find_token(document.body, '\\align ', k - 1, j)
2256 if get_value(document.body, '\\align', al) == "center":
2257 alignment_beg = "\\backslash\nbegin{centering}"
2258 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2259 elif get_value(document.body, '\\align', al) == "left":
2260 alignment_beg = "\\backslash\nbegin{raggedright}"
2261 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2262 elif get_value(document.body, '\\align', al) == "right":
2263 alignment_beg = "\\backslash\nbegin{raggedleft}"
2264 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2265 l = find_end_of_inset(document.body, k)
2267 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2270 continue # escape to the outer loop
2271 m = find_default_layout(document, k + 1, l)
2273 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2278 capend = find_end_of_inset(document.body, cap)
2280 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2284 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2286 lblend = find_end_of_inset(document.body, lbl + 1)
2288 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2290 for line in document.body[lbl:lblend + 1]:
2291 if line.startswith('name '):
2292 label = line.split()[1].strip('"')
2299 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2301 optend = find_end_of_inset(document.body, opt)
2303 document.warning("Malformed LyX document: Missing '\\end_inset' (OptArg).")
2305 optc = find_default_layout(document, opt, optend)
2307 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2309 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2310 for line in document.body[optc:optcend]:
2311 if not line.startswith('\\'):
2312 shortcap += line.strip()
2316 for line in document.body[cap:capend]:
2317 if line in document.body[lbl:lblend]:
2319 elif line in document.body[opt:optend]:
2323 caption += lyxline2latex(document, line, inert)
2325 caption += "\n\\backslash\nlabel{" + label + "}"
2326 subst = '\\begin_layout PlainLayout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2327 '\\begin_layout PlainLayout\n\n}' + alignment_end + \
2328 '\n\\end_layout\n\n\\end_inset\n\n' \
2329 '\\end_layout\n\n\\begin_layout PlainLayout\n'
2330 subst = subst.split('\n')
2331 document.body[l : l+1] = subst
2332 addedLines = len(subst) - 1
2333 # this is before l and so is unchanged by the multiline insertion
2335 del document.body[cap:capend+1]
2336 addedLines -= (capend + 1 - cap)
2337 del document.body[k+1:m-1]
2338 addedLines -= (m - 1 - (k + 1))
2339 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2340 '\\begin_layout PlainLayout\n\n' + alignment_beg + '\n\\backslash\n' \
2342 if len(shortcap) > 0:
2343 insertion = insertion + "[" + shortcap + "]"
2344 if len(caption) > 0:
2345 insertion = insertion + "[" + caption + "]"
2346 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2347 insertion = insertion.split('\n')
2348 document.body[k : k + 1] = insertion
2349 addedLines += len(insertion) - 1
2350 al = find_token(document.body, '\\align ', k - 1, j + addedLines)
2352 del document.body[al]
2354 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2358 def revert_wrapplacement(document):
2359 " Revert placement options wrap floats (wrapfig). "
2362 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2365 e = find_end_of_inset(document.body, i)
2366 j = find_token(document.body, "placement", i + 1, e)
2368 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2371 r = re.compile("placement (o|i|l|r|O|I|L|R)")
2372 m = r.match(document.body[j])
2374 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2376 document.body[j] = "placement " + m.group(1).lower()
2380 def remove_extra_embedded_files(document):
2381 " Remove \extra_embedded_files from buffer params "
2382 i = find_token(document.header, '\\extra_embedded_files', 0)
2385 document.header.pop(i)
2388 def convert_spaceinset(document):
2389 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2391 while i < len(document.body):
2392 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2396 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2397 document.body[i: i+1] = subst
2403 def revert_spaceinset(document):
2404 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2407 i = find_token(document.body, "\\begin_inset Space", i)
2410 j = find_end_of_inset(document.body, i)
2412 document.warning("Malformed LyX document: Could not find end of space inset.")
2415 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2416 del document.body[j]
2419 def convert_hfill(document):
2420 " Convert hfill to space inset "
2423 i = find_token(document.body, "\\hfill", i)
2426 subst = document.body[i].replace('\\hfill', \
2427 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2428 subst = subst.split('\n')
2429 document.body[i : i+1] = subst
2433 def revert_hfills(document):
2434 ' Revert \\hfill commands '
2435 hfill = re.compile(r'\\hfill')
2436 dotfill = re.compile(r'\\dotfill')
2437 hrulefill = re.compile(r'\\hrulefill')
2440 i = find_token(document.body, "\\InsetSpace", i)
2443 if hfill.search(document.body[i]):
2444 document.body[i] = \
2445 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2448 if dotfill.search(document.body[i]):
2449 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2450 '\\begin_inset ERT\nstatus collapsed\n\n' \
2451 '\\begin_layout Standard\n\n\n\\backslash\n' \
2452 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2453 subst = subst.split('\n')
2454 document.body[i : i+1] = subst
2457 if hrulefill.search(document.body[i]):
2458 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2459 '\\begin_inset ERT\nstatus collapsed\n\n' \
2460 '\\begin_layout Standard\n\n\n\\backslash\n' \
2461 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2462 subst = subst.split('\n')
2463 document.body[i : i+1] = subst
2468 def revert_hspace(document):
2469 ' Revert \\InsetSpace \\hspace{} to ERT '
2471 hspace = re.compile(r'\\hspace{}')
2472 hstar = re.compile(r'\\hspace\*{}')
2474 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2477 length = get_value(document.body, '\\length', i+1)
2479 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2481 del document.body[i+1]
2483 if hstar.search(document.body[i]):
2484 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2485 '\\begin_inset ERT\nstatus collapsed\n\n' \
2486 '\\begin_layout Standard\n\n\n\\backslash\n' \
2487 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2488 subst = subst.split('\n')
2489 document.body[i : i+1] = subst
2490 addedLines += len(subst) - 1
2493 if hspace.search(document.body[i]):
2494 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2495 '\\begin_inset ERT\nstatus collapsed\n\n' \
2496 '\\begin_layout Standard\n\n\n\\backslash\n' \
2497 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2498 subst = subst.split('\n')
2499 document.body[i : i+1] = subst
2500 addedLines += len(subst) - 1
2506 def revert_protected_hfill(document):
2507 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2510 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2513 j = find_end_of_inset(document.body, i)
2515 document.warning("Malformed LyX document: Could not find end of space inset.")
2518 del document.body[j]
2519 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2520 '\\begin_inset ERT\nstatus collapsed\n\n' \
2521 '\\begin_layout Standard\n\n\n\\backslash\n' \
2522 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2523 subst = subst.split('\n')
2524 document.body[i : i+1] = subst
2528 def revert_leftarrowfill(document):
2529 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2532 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2535 j = find_end_of_inset(document.body, i)
2537 document.warning("Malformed LyX document: Could not find end of space inset.")
2540 del document.body[j]
2541 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2542 '\\begin_inset ERT\nstatus collapsed\n\n' \
2543 '\\begin_layout Standard\n\n\n\\backslash\n' \
2544 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2545 subst = subst.split('\n')
2546 document.body[i : i+1] = subst
2550 def revert_rightarrowfill(document):
2551 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2554 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2557 j = find_end_of_inset(document.body, i)
2559 document.warning("Malformed LyX document: Could not find end of space inset.")
2562 del document.body[j]
2563 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2564 '\\begin_inset ERT\nstatus collapsed\n\n' \
2565 '\\begin_layout Standard\n\n\n\\backslash\n' \
2566 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2567 subst = subst.split('\n')
2568 document.body[i : i+1] = subst
2572 def revert_upbracefill(document):
2573 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2576 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2579 j = find_end_of_inset(document.body, i)
2581 document.warning("Malformed LyX document: Could not find end of space inset.")
2584 del document.body[j]
2585 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2586 '\\begin_inset ERT\nstatus collapsed\n\n' \
2587 '\\begin_layout Standard\n\n\n\\backslash\n' \
2588 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2589 subst = subst.split('\n')
2590 document.body[i : i+1] = subst
2594 def revert_downbracefill(document):
2595 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2598 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2601 j = find_end_of_inset(document.body, i)
2603 document.warning("Malformed LyX document: Could not find end of space inset.")
2606 del document.body[j]
2607 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2608 '\\begin_inset ERT\nstatus collapsed\n\n' \
2609 '\\begin_layout Standard\n\n\n\\backslash\n' \
2610 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2611 subst = subst.split('\n')
2612 document.body[i : i+1] = subst
2616 def revert_local_layout(document):
2617 ' Revert local layout headers.'
2620 i = find_token(document.header, "\\begin_local_layout", i)
2623 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2625 # this should not happen
2627 document.header[i : j + 1] = []
2630 def convert_pagebreaks(document):
2631 ' Convert inline Newpage insets to new format '
2634 i = find_token(document.body, '\\newpage', i)
2637 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2641 i = find_token(document.body, '\\pagebreak', i)
2644 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2648 i = find_token(document.body, '\\clearpage', i)
2651 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2655 i = find_token(document.body, '\\cleardoublepage', i)
2658 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2662 def revert_pagebreaks(document):
2663 ' Revert \\begin_inset Newpage to previous inline format '
2666 i = find_token(document.body, '\\begin_inset Newpage', i)
2669 j = find_end_of_inset(document.body, i)
2671 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2674 del document.body[j]
2675 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2676 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2677 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2678 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2681 def convert_linebreaks(document):
2682 ' Convert inline Newline insets to new format '
2685 i = find_token(document.body, '\\newline', i)
2688 document.body[i:i+1] = ['\\begin_inset Newline newline',
2692 i = find_token(document.body, '\\linebreak', i)
2695 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2699 def revert_linebreaks(document):
2700 ' Revert \\begin_inset Newline to previous inline format '
2703 i = find_token(document.body, '\\begin_inset Newline', i)
2706 j = find_end_of_inset(document.body, i)
2708 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2711 del document.body[j]
2712 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2713 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2716 def convert_japanese_plain(document):
2717 ' Set language japanese-plain to japanese '
2719 if document.language == "japanese-plain":
2720 document.language = "japanese"
2721 i = find_token(document.header, "\\language", 0)
2723 document.header[i] = "\\language japanese"
2726 j = find_token(document.body, "\\lang japanese-plain", j)
2729 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2733 def revert_pdfpages(document):
2734 ' Revert pdfpages external inset to ERT '
2737 i = find_token(document.body, "\\begin_inset External", i)
2740 j = find_end_of_inset(document.body, i)
2742 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2745 if get_value(document.body, 'template', i, j) == "PDFPages":
2746 filename = get_value(document.body, 'filename', i, j)
2748 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2749 for k in range(i, j):
2750 m = r.match(document.body[k])
2753 angle = get_value(document.body, 'rotateAngle', i, j)
2754 width = get_value(document.body, 'width', i, j)
2755 height = get_value(document.body, 'height', i, j)
2756 scale = get_value(document.body, 'scale', i, j)
2757 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2761 options += ",angle=" + angle
2763 options += "angle=" + angle
2766 options += ",width=" + convert_len(width)
2768 options += "width=" + convert_len(width)
2771 options += ",height=" + convert_len(height)
2773 options += "height=" + convert_len(height)
2776 options += ",scale=" + scale
2778 options += "scale=" + scale
2779 if keepAspectRatio != '':
2781 options += ",keepaspectratio"
2783 options += "keepaspectratio"
2785 options = '[' + options + ']'
2786 del document.body[i+1:j+1]
2787 document.body[i:i+1] = ['\\begin_inset ERT',
2790 '\\begin_layout Standard',
2793 'includepdf' + options + '{' + filename + '}',
2797 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2803 def revert_mexican(document):
2804 ' Set language Spanish(Mexico) to Spanish '
2806 if document.language == "spanish-mexico":
2807 document.language = "spanish"
2808 i = find_token(document.header, "\\language", 0)
2810 document.header[i] = "\\language spanish"
2813 j = find_token(document.body, "\\lang spanish-mexico", j)
2816 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2820 def remove_embedding(document):
2821 ' Remove embed tag from all insets '
2822 revert_inset_embedding(document, 'Graphics')
2823 revert_inset_embedding(document, 'External')
2824 revert_inset_embedding(document, 'CommandInset include')
2825 revert_inset_embedding(document, 'CommandInset bibtex')
2828 def revert_master(document):
2829 ' Remove master param '
2830 i = find_token(document.header, "\\master", 0)
2832 del document.header[i]
2835 def revert_graphics_group(document):
2836 ' Revert group information from graphics insets '
2839 i = find_token(document.body, "\\begin_inset Graphics", i)
2842 j = find_end_of_inset(document.body, i)
2844 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2847 k = find_token(document.body, " groupId", i, j)
2851 del document.body[k]
2855 def update_apa_styles(document):
2856 ' Replace obsolete styles '
2858 if document.textclass != "apa":
2861 obsoletedby = { "Acknowledgments": "Acknowledgements",
2862 "Section*": "Section",
2863 "Subsection*": "Subsection",
2864 "Subsubsection*": "Subsubsection",
2865 "Paragraph*": "Paragraph",
2866 "Subparagraph*": "Subparagraph"}
2869 i = find_token(document.body, "\\begin_layout", i)
2873 layout = document.body[i][14:]
2874 if layout in obsoletedby:
2875 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2880 def convert_paper_sizes(document):
2881 ' exchange size options legalpaper and executivepaper to correct order '
2882 # routine is needed to fix http://www.lyx.org/trac/ticket/4868
2885 i = find_token(document.header, "\\papersize executivepaper", 0)
2887 document.header[i] = "\\papersize legalpaper"
2889 j = find_token(document.header, "\\papersize legalpaper", 0)
2891 document.header[j] = "\\papersize executivepaper"
2894 def revert_paper_sizes(document):
2895 ' exchange size options legalpaper and executivepaper to correct order '
2898 i = find_token(document.header, "\\papersize executivepaper", 0)
2900 document.header[i] = "\\papersize legalpaper"
2902 j = find_token(document.header, "\\papersize legalpaper", 0)
2904 document.header[j] = "\\papersize executivepaper"
2907 def convert_InsetSpace(document):
2908 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2911 i = find_token(document.body, "\\begin_inset Space", i)
2914 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2917 def revert_InsetSpace(document):
2918 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2921 i = find_token(document.body, "\\begin_inset space", i)
2924 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2927 def convert_display_enum(document):
2928 " Convert 'display foo' to 'display false/true'"
2931 i = find_token(document.body, "\tdisplay", i)
2934 val = get_value(document.body, 'display', i)
2936 document.body[i] = document.body[i].replace('none', 'false')
2937 if val == "default":
2938 document.body[i] = document.body[i].replace('default', 'true')
2939 if val == "monochrome":
2940 document.body[i] = document.body[i].replace('monochrome', 'true')
2941 if val == "grayscale":
2942 document.body[i] = document.body[i].replace('grayscale', 'true')
2944 document.body[i] = document.body[i].replace('color', 'true')
2945 if val == "preview":
2946 document.body[i] = document.body[i].replace('preview', 'true')
2950 def revert_display_enum(document):
2951 " Revert 'display false/true' to 'display none/color'"
2954 i = find_token(document.body, "\tdisplay", i)
2957 val = get_value(document.body, 'display', i)
2959 document.body[i] = document.body[i].replace('false', 'none')
2961 document.body[i] = document.body[i].replace('true', 'default')
2965 def remove_fontsCJK(document):
2966 ' Remove font_cjk param '
2967 i = find_token(document.header, "\\font_cjk", 0)
2969 del document.header[i]
2972 def convert_plain_layout(document):
2973 " Convert 'PlainLayout' to 'Plain Layout'"
2976 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2979 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2980 '\\begin_layout Plain Layout')
2984 def revert_plain_layout(document):
2985 " Revert 'Plain Layout' to 'PlainLayout'"
2988 i = find_token(document.body, '\\begin_layout Plain Layout', i)
2991 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2992 '\\begin_layout PlainLayout')
2996 def revert_plainlayout(document):
2997 " Revert 'PlainLayout' to 'Standard'"
3000 i = find_token(document.body, '\\begin_layout PlainLayout', i)
3003 # This will be incorrect for some document classes, since Standard is not always
3004 # the default. But (a) it is probably the best we can do and (b) it will actually
3005 # work, in fact, since an unknown layout will be converted to default.
3006 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
3007 '\\begin_layout Standard')
3011 def revert_polytonicgreek(document):
3012 "Set language polytonic Greek to Greek"
3014 if document.language == "polutonikogreek":
3015 document.language = "greek"
3016 i = find_token(document.header, "\\language", 0)
3018 document.header[i] = "\\language greek"
3021 j = find_token(document.body, "\\lang polutonikogreek", j)
3024 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
3028 def revert_removed_modules(document):
3031 i = find_token(document.header, "\\begin_remove_modules", i)
3034 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
3036 # this should not happen
3038 document.header[i : j + 1] = []
3041 def add_plain_layout(document):
3044 i = find_token(document.body, "\\begin_layout", i)
3047 if len(document.body[i].split()) == 1:
3048 document.body[i] = "\\begin_layout Plain Layout"
3052 def revert_tabulators(document):
3053 "Revert tabulators to 4 spaces"
3056 i = find_token(document.body, "\t", i)
3059 document.body[i] = document.body[i].replace("\t", " ")
3063 def revert_tabsize(document):
3064 "Revert the tabsize parameter of listings"
3068 # either it is the only parameter
3069 i = find_token(document.body, 'lstparams "tabsize=4"', i)
3071 del document.body[i]
3073 j = find_token(document.body, "lstparams", j)
3076 pos = document.body[j].find(",tabsize=")
3077 document.body[j] = document.body[j][:pos] + '"'
3082 def revert_mongolian(document):
3083 "Set language Mongolian to English"
3085 if document.language == "mongolian":
3086 document.language = "english"
3087 i = find_token(document.header, "\\language", 0)
3089 document.header[i] = "\\language english"
3092 j = find_token(document.body, "\\lang mongolian", j)
3095 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
3099 def revert_default_options(document):
3100 ' Remove param use_default_options '
3101 i = find_token(document.header, "\\use_default_options", 0)
3103 del document.header[i]
3106 def convert_default_options(document):
3107 ' Add param use_default_options and set it to false '
3108 i = find_token(document.header, "\\textclass", 0)
3110 document.warning("Malformed LyX document: Missing `\\textclass'.")
3112 document.header.insert(i, '\\use_default_options false')
3115 def revert_backref_options(document):
3116 ' Revert option pdf_backref=page to pagebackref '
3117 i = find_token(document.header, "\\pdf_backref page", 0)
3119 document.header[i] = "\\pdf_pagebackref true"
3122 def convert_backref_options(document):
3123 ' We have changed the option pagebackref to backref=true '
3124 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3126 document.header[i] = "\\pdf_backref page"
3127 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3129 del document.header[j]
3130 # backref=true was not a valid option, we meant backref=section
3131 k = find_token(document.header, "\\pdf_backref true", 0)
3132 if k != -1 and i != -1:
3133 del document.header[k]
3134 elif k != -1 and j != -1:
3135 document.header[k] = "\\pdf_backref section"
3138 def convert_charstyle_element(document):
3139 "Convert CharStyle to Element for docbook backend"
3140 if document.backend != "docbook":
3144 i = find_token(document.body, "\\begin_inset Flex CharStyle:", i)
3147 document.body[i] = document.body[i].replace('\\begin_inset Flex CharStyle:',
3148 '\\begin_inset Flex Element:')
3150 def revert_charstyle_element(document):
3151 "Convert Element to CharStyle for docbook backend"
3152 if document.backend != "docbook":
3156 i = find_token(document.body, "\\begin_inset Flex Element:", i)
3159 document.body[i] = document.body[i].replace('\\begin_inset Flex Element:',
3160 '\\begin_inset Flex CharStyle:')
3166 supported_versions = ["1.6.0","1.6"]
3167 convert = [[277, [fix_wrong_tables]],
3168 [278, [close_begin_deeper]],
3169 [279, [long_charstyle_names]],
3170 [280, [axe_show_label]],
3173 [283, [convert_flex]],
3177 [287, [convert_wrapfig_options]],
3178 [288, [convert_inset_command]],
3179 [289, [convert_latexcommand_index]],
3182 [292, [convert_japanese_cjk]],
3184 [294, [convert_pdf_options]],
3185 [295, [convert_htmlurl, convert_url]],
3186 [296, [convert_include]],
3187 [297, [convert_usorbian]],
3188 [298, [convert_macro_global]],
3193 [303, [convert_serbocroatian]],
3194 [304, [convert_framed_notes]],
3201 [311, [convert_ams_classes]],
3203 [313, [convert_module_names]],
3206 [316, [convert_subfig]],
3209 [319, [convert_spaceinset, convert_hfill]],
3211 [321, [convert_tablines]],
3212 [322, [convert_plain_layout]],
3213 [323, [convert_pagebreaks]],
3214 [324, [convert_linebreaks]],
3215 [325, [convert_japanese_plain]],
3218 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3221 [331, [convert_ltcaption]],
3223 [333, [update_apa_styles]],
3224 [334, [convert_paper_sizes]],
3225 [335, [convert_InsetSpace]],
3227 [337, [convert_display_enum]],
3230 [340, [add_plain_layout]],
3233 [343, [convert_default_options]],
3234 [344, [convert_backref_options]],
3235 [345, [convert_charstyle_element]]
3238 revert = [[344, [revert_charstyle_element]],
3239 [343, [revert_backref_options]],
3240 [342, [revert_default_options]],
3241 [341, [revert_mongolian]],
3242 [340, [revert_tabulators, revert_tabsize]],
3244 [338, [revert_removed_modules]],
3245 [337, [revert_polytonicgreek]],
3246 [336, [revert_display_enum]],
3247 [335, [remove_fontsCJK]],
3248 [334, [revert_InsetSpace]],
3249 [333, [revert_paper_sizes]],
3251 [331, [revert_graphics_group]],
3252 [330, [revert_ltcaption]],
3253 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
3254 [328, [revert_master]],
3256 [326, [revert_mexican]],
3257 [325, [revert_pdfpages]],
3259 [323, [revert_linebreaks]],
3260 [322, [revert_pagebreaks]],
3261 [321, [revert_local_layout, revert_plain_layout]],
3262 [320, [revert_tablines]],
3263 [319, [revert_protected_hfill]],
3264 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3265 [317, [remove_extra_embedded_files]],
3266 [316, [revert_wrapplacement]],
3267 [315, [revert_subfig]],
3268 [314, [revert_colsep, revert_plainlayout]],
3270 [312, [revert_module_names]],
3271 [311, [revert_rotfloat, revert_widesideways]],
3272 [310, [revert_external_embedding]],
3273 [309, [revert_btprintall]],
3274 [308, [revert_nocite]],
3275 [307, [revert_serbianlatin]],
3276 [306, [revert_slash, revert_nobreakdash]],
3277 [305, [revert_interlingua]],
3278 [304, [revert_bahasam]],
3279 [303, [revert_framed_notes]],
3281 [301, [revert_latin, revert_samin]],
3282 [300, [revert_linebreak]],
3283 [299, [revert_pagebreak]],
3284 [298, [revert_hyperlinktype]],
3285 [297, [revert_macro_optional_params]],
3286 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3287 [295, [revert_include]],
3288 [294, [revert_href, revert_url]],
3289 [293, [revert_pdf_options_2]],
3290 [292, [revert_inset_info]],
3291 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3292 [290, [revert_vietnamese]],
3293 [289, [revert_wraptable]],
3294 [288, [revert_latexcommand_index]],
3295 [287, [revert_inset_command]],
3296 [286, [revert_wrapfig_options]],
3297 [285, [revert_pdf_options]],
3298 [284, [remove_inzip_options]],
3300 [282, [revert_flex]],
3302 [280, [revert_begin_modules]],
3303 [279, [revert_show_label]],
3304 [278, [revert_long_charstyle_names]],
3310 if __name__ == "__main__":