1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2008 The LyX Team <lyx-devel@lists.lyx.org>
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 """ Convert files to the file format generated by lyx 1.6"""
25 from parser_tools import find_token, find_end_of, find_tokens, get_value, get_value_string
27 ####################################################################
28 # Private helper functions
30 def find_end_of_inset(lines, i):
31 " Find end of inset, where lines[i] is included."
32 return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
36 # document.body[i] = wrap_insert_ert(...)
37 # wrap_into_ert may returns a multiline string, which should NOT appear
38 # in document.body. Insetad, do something like this:
39 # subst = wrap_inset_ert(...)
40 # subst = subst.split('\n')
41 # document.body[i:i+1] = subst
43 # where the last statement resets the counter to accord with the added
45 def wrap_into_ert(string, src, dst):
46 '''Within string, replace occurrences of src with dst, wrapped into ERT
47 E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is:
48 sch<ERT>\\backslash</ERT>"on'''
49 return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
50 + dst + '\n\\end_layout\n\\end_inset\n')
52 def put_cmd_in_ert(string):
53 for rep in unicode_reps:
54 string = string.replace(rep[1], rep[0].replace('\\\\', '\\'))
55 string = string.replace('\\', "\\backslash\n")
56 string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n" \
57 + string + "\n\\end_layout\n\\end_inset"
60 def add_to_preamble(document, text):
61 """ Add text to the preamble if it is not already there.
62 Only the first line is checked!"""
64 if find_token(document.preamble, text[0], 0) != -1:
67 document.preamble.extend(text)
69 def insert_to_preamble(index, document, text):
70 """ Insert text to the preamble at a given line"""
72 document.preamble.insert(index, text)
74 # Convert a LyX length into a LaTeX length
76 units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
77 "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
78 "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
80 # Convert LyX units to LaTeX units
81 for unit in units.keys():
82 if len.find(unit) != -1:
83 len = '%f' % (len2value(len) / 100)
84 len = len.strip('0') + units[unit]
89 # Return the value of len without the unit in numerical form.
91 result = re.search('([+-]?[0-9.]+)', len)
93 return float(result.group(1))
97 # Unfortunately, this doesn't really work, since Standard isn't always default.
98 # But it's as good as we can do right now.
99 def find_default_layout(document, start, end):
100 l = find_token(document.body, "\\begin_layout Standard", start, end)
102 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
104 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
107 def get_option(document, m, option, default):
108 l = document.body[m].find(option)
111 val = document.body[m][l:].split('"')[1]
114 def remove_option(document, m, option):
115 l = document.body[m].find(option)
117 val = document.body[m][l:].split('"')[1]
118 document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
121 def set_option(document, m, option, value):
122 l = document.body[m].find(option)
124 oldval = document.body[m][l:].split('"')[1]
125 l = l + len(option + '="')
126 document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
128 document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
132 def read_unicodesymbols():
133 " Read the unicodesymbols list of unicode characters and corresponding commands."
134 pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
135 fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
137 # Two backslashes, followed by some non-word character, and then a character
138 # in brackets. The idea is to check for constructs like: \"{u}, which is how
139 # they are written in the unicodesymbols file; but they can also be written
140 # as: \"u or even \" u.
141 r = re.compile(r'\\\\(\W)\{(\w)\}')
142 for line in fp.readlines():
143 if line[0] != '#' and line.strip() != "":
144 line=line.replace(' "',' ') # remove all quotation marks with spaces before
145 line=line.replace('" ',' ') # remove all quotation marks with spaces after
146 line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
148 [ucs4,command,dead] = line.split(None,2)
149 if command[0:1] != "\\":
151 spec_chars.append([command, unichr(eval(ucs4))])
157 # If the character is a double-quote, then we need to escape it, too,
158 # since it is done that way in the LyX file.
159 if m.group(1) == "\"":
162 command += m.group(1) + m.group(2)
163 commandbl += m.group(1) + ' ' + m.group(2)
164 spec_chars.append([command, unichr(eval(ucs4))])
165 spec_chars.append([commandbl, unichr(eval(ucs4))])
170 def extract_argument(line):
171 'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
176 bracere = re.compile("(\s*)(.*)")
177 n = bracere.match(line)
178 whitespace = n.group(1)
181 if brace != "[" and brace != "{":
205 # We never found the matching brace
206 # So, to be on the safe side, let's just return everything
207 # which will then get wrapped as ERT
209 return (line[:pos + 1], line[pos + 1:])
212 def latex2ert(line, isindex):
213 '''Converts LaTeX commands into ERT. line may well be a multi-line
214 string when it is returned.'''
219 ## FIXME Escaped \ ??
220 # This regex looks for a LaTeX command---i.e., something of the form
221 # "\alPhaStuFF", or "\X", where X is any character---where the command
222 # may also be preceded by an additional backslash, which is how it would
223 # appear (e.g.) in an InsetIndex.
224 labelre = re.compile(r'(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)')
226 m = labelre.match(line)
233 (arg, rest) = extract_argument(end)
238 # If we wanted to put labels into an InsetLabel, for example, then we
239 # would just need to test here for cmd == "label" and then take some
240 # appropriate action, i.e., to use arg to get the content and then
241 # wrap it appropriately.
242 cmd = put_cmd_in_ert(cmd)
243 retval += "\n" + cmd + "\n"
245 m = labelre.match(line)
246 # put all remaining braces in ERT
247 line = wrap_into_ert(line, '}', '}')
248 line = wrap_into_ert(line, '{', '{')
250 # active character that is not available in all font encodings
251 line = wrap_into_ert(line, '|', '|')
256 unicode_reps = read_unicodesymbols()
259 #Might should do latex2ert first, then deal with stuff that DOESN'T
260 #end up inside ERT. That routine could be modified so that it returned
261 #a list of lines, and we could then skip ERT bits and only deal with
263 def latex2lyx(data, isindex):
264 '''Takes a string, possibly multi-line, and returns the result of
265 converting LaTeX constructs into LyX constructs. Returns a list of
266 lines, suitable for insertion into document.body.
267 The bool isindex specifies whether we are in an index macro (which
268 has some specific active characters that need to be ERTed).'''
274 # Convert LaTeX to Unicode
275 # Commands of this sort need to be checked to make sure they are
276 # followed by a non-alpha character, lest we replace too much.
277 hardone = re.compile(r'^\\\\[a-zA-Z]+$')
279 for rep in unicode_reps:
280 if hardone.match(rep[0]):
283 pos = data.find(rep[0], pos)
286 nextpos = pos + len(rep[0])
287 if nextpos < len(data) and data[nextpos].isalpha():
288 # not the end of that command
291 data = data[:pos] + rep[1] + data[nextpos:]
294 data = data.replace(rep[0], rep[1])
298 data = wrap_into_ert(data, r'\"', '"')
300 data = data.replace('\\\\', '\\')
303 mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
304 lines = data.split('\n')
306 #document.warning("LINE: " + line)
307 #document.warning(str(i) + ":" + document.body[i])
308 #document.warning("LAST: " + document.body[-1])
313 f = m.group(2).replace('\\\\', '\\')
317 s = latex2ert(s, isindex)
318 subst = s.split('\n')
320 retval.append("\\begin_inset Formula " + f)
321 retval.append("\\end_inset")
323 # Handle whatever is left, which is just text
324 g = latex2ert(g, isindex)
325 subst = g.split('\n')
330 def lyxline2latex(document, line, inert):
331 'Convert some LyX stuff into corresponding LaTeX stuff line-wise, as best we can.'
332 if line.startswith("\\begin_inset Formula"):
334 elif line.startswith("\\begin_inset Quotes"):
335 # For now, we do a very basic reversion. Someone who understands
336 # quotes is welcome to fix it up.
337 qtype = line[20:].strip()
351 elif line.isspace() or \
352 line.startswith("\\begin_layout") or \
353 line.startswith("\\end_layout") or \
354 line.startswith("\\begin_inset") or \
355 line.startswith("\\end_inset") or \
356 line.startswith("\\lang") or \
357 line.strip() == "status collapsed" or \
358 line.strip() == "status open":
362 # this needs to be added to the preamble because of cases like
363 # \textmu, \textbackslash, etc.
364 add_to_preamble(document, ['% added by lyx2lyx for converted entries',
365 '\\@ifundefined{textmu}',
366 ' {\\usepackage{textcomp}}{}'])
367 # a lossless reversion is not possible
368 # try at least to handle some common insets and settings
370 line = line.replace(r'\backslash', '\\')
372 line = line.replace('&', '\\&{}')
373 line = line.replace('#', '\\#{}')
374 line = line.replace('^', '\\^{}')
375 line = line.replace('%', '\\%{}')
376 line = line.replace('_', '\\_{}')
377 line = line.replace('$', '\\${}')
379 # Do the LyX text --> LaTeX conversion
380 for rep in unicode_reps:
381 line = line.replace(rep[1], rep[0].replace('\\\\', '\\') + "{}")
382 line = line.replace(r'\backslash', r'\textbackslash{}')
383 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
384 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
385 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
386 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
387 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
388 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
389 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
390 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
391 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
395 def lyx2latex(document, lines):
396 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
397 # clean up multiline stuff
401 for curline in range(len(lines)):
402 line = lines[curline]
403 if line.startswith("\\begin_inset ERT"):
404 # We don't want to replace things inside ERT, so figure out
405 # where the end of the inset is.
406 ert_end = find_end_of_inset(lines, curline + 1)
408 inert = ert_end >= curline
409 content += lyxline2latex(document, lines[curline], inert)
414 ####################################################################
416 def convert_ltcaption(document):
419 i = find_token(document.body, "\\begin_inset Tabular", i)
422 j = find_end_of_inset(document.body, i + 1)
424 document.warning("Malformed LyX document: Could not find end of tabular.")
427 nrows = int(document.body[i+1].split('"')[3])
428 ncols = int(document.body[i+1].split('"')[5])
431 for k in range(nrows):
432 m = find_token(document.body, "<row", m)
435 for k in range(ncols):
436 m = find_token(document.body, "<cell", m)
438 mend = find_token(document.body, "</cell>", m + 1)
439 # first look for caption insets
440 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
441 # then look for ERT captions
443 mcap = find_token(document.body, "caption", m + 1, mend)
445 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
448 if caption == 'true':
450 set_option(document, r, 'caption', 'true')
451 set_option(document, m, 'multicolumn', '1')
452 set_option(document, m, 'bottomline', 'false')
453 set_option(document, m, 'topline', 'false')
454 set_option(document, m, 'rightline', 'false')
455 set_option(document, m, 'leftline', 'false')
456 #j = find_end_of_inset(document.body, j + 1)
458 set_option(document, m, 'multicolumn', '2')
465 #FIXME Use of wrap_into_ert can confuse lyx2lyx
466 def revert_ltcaption(document):
469 i = find_token(document.body, "\\begin_inset Tabular", i)
472 j = find_end_of_inset(document.body, i + 1)
474 document.warning("Malformed LyX document: Could not find end of tabular.")
479 nrows = int(document.body[i+1].split('"')[3])
480 ncols = int(document.body[i+1].split('"')[5])
482 for k in range(nrows):
483 m = find_token(document.body, "<row", m)
484 caption = get_option(document, m, 'caption', 'false')
485 if caption == 'true':
486 remove_option(document, m, 'caption')
487 for k in range(ncols):
488 m = find_token(document.body, "<cell", m)
489 remove_option(document, m, 'multicolumn')
491 m = find_token(document.body, "\\begin_inset Caption", m)
494 m = find_end_of_inset(document.body, m + 1)
495 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
501 def convert_tablines(document):
504 i = find_token(document.body, "\\begin_inset Tabular", i)
506 # LyX 1.3 inserted an extra space between \begin_inset
507 # and Tabular so let us try if this is the case and fix it.
508 i = find_token(document.body, "\\begin_inset Tabular", i)
512 document.body[i] = "\\begin_inset Tabular"
513 j = find_end_of_inset(document.body, i + 1)
515 document.warning("Malformed LyX document: Could not find end of tabular.")
519 nrows = int(document.body[i+1].split('"')[3])
520 ncols = int(document.body[i+1].split('"')[5])
523 for k in range(ncols):
524 m = find_token(document.body, "<column", m)
525 left = get_option(document, m, 'leftline', 'false')
526 right = get_option(document, m, 'rightline', 'false')
527 col_info.append([left, right])
528 remove_option(document, m, 'leftline')
529 remove_option(document, m, 'rightline')
533 for k in range(nrows):
534 m = find_token(document.body, "<row", m)
535 top = get_option(document, m, 'topline', 'false')
536 bottom = get_option(document, m, 'bottomline', 'false')
537 row_info.append([top, bottom])
538 remove_option(document, m, 'topline')
539 remove_option(document, m, 'bottomline')
544 for k in range(nrows*ncols):
545 m = find_token(document.body, "<cell", m)
546 mc_info.append(get_option(document, m, 'multicolumn', '0'))
549 for l in range(nrows):
550 for k in range(ncols):
551 m = find_token(document.body, '<cell', m)
552 if mc_info[l*ncols + k] == '0':
553 r = set_option(document, m, 'topline', row_info[l][0])
554 r = set_option(document, m, 'bottomline', row_info[l][1])
555 r = set_option(document, m, 'leftline', col_info[k][0])
556 r = set_option(document, m, 'rightline', col_info[k][1])
557 elif mc_info[l*ncols + k] == '1':
559 while s < ncols and mc_info[l*ncols + s] == '2':
561 if s < ncols and mc_info[l*ncols + s] != '1':
562 r = set_option(document, m, 'rightline', col_info[k][1])
563 if k > 0 and mc_info[l*ncols + k - 1] == '0':
564 r = set_option(document, m, 'leftline', col_info[k][0])
569 def revert_tablines(document):
572 i = find_token(document.body, "\\begin_inset Tabular", i)
575 j = find_end_of_inset(document.body, i + 1)
577 document.warning("Malformed LyX document: Could not find end of tabular.")
581 nrows = int(document.body[i+1].split('"')[3])
582 ncols = int(document.body[i+1].split('"')[5])
585 for k in range(nrows*ncols):
586 m = find_token(document.body, "<cell", m)
587 top = get_option(document, m, 'topline', 'false')
588 bottom = get_option(document, m, 'bottomline', 'false')
589 left = get_option(document, m, 'leftline', 'false')
590 right = get_option(document, m, 'rightline', 'false')
591 lines.append([top, bottom, left, right])
594 # we will want to ignore longtable captions
597 for k in range(nrows):
598 m = find_token(document.body, "<row", m)
599 caption = get_option(document, m, 'caption', 'false')
600 caption_info.append([caption])
605 for k in range(ncols):
606 m = find_token(document.body, "<column", m)
608 for l in range(nrows):
609 left = lines[l*ncols + k][2]
610 if left == 'false' and caption_info[l] == 'false':
612 set_option(document, m, 'leftline', left)
614 for l in range(nrows):
615 right = lines[l*ncols + k][3]
616 if right == 'false' and caption_info[l] == 'false':
618 set_option(document, m, 'rightline', right)
622 for k in range(nrows):
623 m = find_token(document.body, "<row", m)
625 for l in range(ncols):
626 top = lines[k*ncols + l][0]
629 if caption_info[k] == 'false':
631 set_option(document, m, 'topline', top)
633 for l in range(ncols):
634 bottom = lines[k*ncols + l][1]
635 if bottom == 'false':
637 if caption_info[k] == 'false':
639 set_option(document, m, 'bottomline', bottom)
645 def fix_wrong_tables(document):
648 i = find_token(document.body, "\\begin_inset Tabular", i)
651 j = find_end_of_inset(document.body, i + 1)
653 document.warning("Malformed LyX document: Could not find end of tabular.")
657 nrows = int(document.body[i+1].split('"')[3])
658 ncols = int(document.body[i+1].split('"')[5])
660 for l in range(nrows):
662 for k in range(ncols):
663 m = find_token(document.body, '<cell', m)
665 if document.body[m].find('multicolumn') != -1:
666 multicol_cont = int(document.body[m].split('"')[1])
668 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
669 document.body[m] = document.body[m][:5] + document.body[m][21:]
672 prev_multicolumn = multicol_cont
679 def close_begin_deeper(document):
683 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
688 if document.body[i][:13] == "\\begin_deeper":
695 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
698 def long_charstyle_names(document):
701 i = find_token(document.body, "\\begin_inset CharStyle", i)
704 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
707 def revert_long_charstyle_names(document):
710 i = find_token(document.body, "\\begin_inset CharStyle", i)
713 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
717 def axe_show_label(document):
720 i = find_token(document.body, "\\begin_inset CharStyle", i)
723 if document.body[i + 1].find("show_label") != -1:
724 if document.body[i + 1].find("true") != -1:
725 document.body[i + 1] = "status open"
726 del document.body[ i + 2]
728 if document.body[i + 1].find("false") != -1:
729 document.body[i + 1] = "status collapsed"
730 del document.body[ i + 2]
732 document.warning("Malformed LyX document: show_label neither false nor true.")
734 document.warning("Malformed LyX document: show_label missing in CharStyle.")
739 def revert_show_label(document):
742 i = find_token(document.body, "\\begin_inset CharStyle", i)
745 if document.body[i + 1].find("status open") != -1:
746 document.body.insert(i + 1, "show_label true")
748 if document.body[i + 1].find("status collapsed") != -1:
749 document.body.insert(i + 1, "show_label false")
751 document.warning("Malformed LyX document: no legal status line in CharStyle.")
754 def revert_begin_modules(document):
757 i = find_token(document.header, "\\begin_modules", i)
760 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
762 # this should not happen
764 document.header[i : j + 1] = []
766 def convert_flex(document):
767 "Convert CharStyle to Flex"
770 i = find_token(document.body, "\\begin_inset CharStyle", i)
773 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
775 def revert_flex(document):
776 "Convert Flex to CharStyle"
779 i = find_token(document.body, "\\begin_inset Flex", i)
782 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
785 def revert_pdf_options(document):
786 "Revert PDF options for hyperref."
787 # store the PDF options and delete the entries from the Lyx file
795 bookmarksnumbered = ""
797 bookmarksopenlevel = ""
805 i = find_token(document.header, "\\use_hyperref", i)
807 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
808 del document.header[i]
809 i = find_token(document.header, "\\pdf_store_options", i)
811 del document.header[i]
812 i = find_token(document.header, "\\pdf_title", 0)
814 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
815 title = ' pdftitle={' + title + '}'
816 del document.header[i]
817 i = find_token(document.header, "\\pdf_author", 0)
819 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
821 author = ' pdfauthor={' + author + '}'
823 author = ',\n pdfauthor={' + author + '}'
824 del document.header[i]
825 i = find_token(document.header, "\\pdf_subject", 0)
827 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
828 if title == "" and author == "":
829 subject = ' pdfsubject={' + subject + '}'
831 subject = ',\n pdfsubject={' + subject + '}'
832 del document.header[i]
833 i = find_token(document.header, "\\pdf_keywords", 0)
835 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
836 if title == "" and author == "" and subject == "":
837 keywords = ' pdfkeywords={' + keywords + '}'
839 keywords = ',\n pdfkeywords={' + keywords + '}'
840 del document.header[i]
841 i = find_token(document.header, "\\pdf_bookmarks", 0)
843 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
844 bookmarks = ',\n bookmarks=' + bookmarks
845 del document.header[i]
846 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
848 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
849 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
850 del document.header[i]
851 i = find_token(document.header, "\\pdf_bookmarksopen", i)
853 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
854 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
855 del document.header[i]
856 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
858 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
859 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
860 del document.header[i]
861 i = find_token(document.header, "\\pdf_breaklinks", i)
863 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
864 breaklinks = ',\n breaklinks=' + breaklinks
865 del document.header[i]
866 i = find_token(document.header, "\\pdf_pdfborder", i)
868 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
869 if pdfborder == 'true':
870 pdfborder = ',\n pdfborder={0 0 0}'
872 pdfborder = ',\n pdfborder={0 0 1}'
873 del document.header[i]
874 i = find_token(document.header, "\\pdf_colorlinks", i)
876 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
877 colorlinks = ',\n colorlinks=' + colorlinks
878 del document.header[i]
879 i = find_token(document.header, "\\pdf_backref", i)
881 backref = get_value_string(document.header, '\\pdf_backref', 0)
882 backref = ',\n backref=' + backref
883 del document.header[i]
884 i = find_token(document.header, "\\pdf_pagebackref", i)
886 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
887 pagebackref = ',\n pagebackref=' + pagebackref
888 del document.header[i]
889 i = find_token(document.header, "\\pdf_pagemode", 0)
891 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
892 pagemode = ',\n pdfpagemode=' + pagemode
893 del document.header[i]
894 i = find_token(document.header, "\\pdf_quoted_options", 0)
896 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
897 if title == "" and author == "" and subject == "" and keywords == "":
898 otheroptions = ' ' + otheroptions
900 otheroptions = ',\n ' + otheroptions
901 del document.header[i]
903 # write to the preamble when hyperref was used
905 # preamble write preparations
906 # bookmark numbers are only output when they are turned on
907 if bookmarksopen == ',\n bookmarksopen=true':
908 bookmarksopen = bookmarksopen + bookmarksopenlevel
909 if bookmarks == ',\n bookmarks=true':
910 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
912 bookmarks = bookmarks
913 # hypersetup is only output when there are things to be set up
914 setupstart = '\\hypersetup{%\n'
916 if otheroptions == "" and title == "" and author == ""\
917 and subject == "" and keywords == "":
921 # babel must be loaded before hyperref and hyperref the first part
922 # of the preamble, like in LyX 1.6
923 insert_to_preamble(0, document,
924 '% Commands inserted by lyx2lyx for PDF properties\n'
925 + '\\usepackage{babel}\n'
926 + '\\usepackage[unicode=true'
945 def remove_inzip_options(document):
946 "Remove inzipName and embed options from the Graphics inset"
949 i = find_token(document.body, "\\begin_inset Graphics", i)
952 j = find_end_of_inset(document.body, i + 1)
955 document.warning("Malformed LyX document: Could not find end of graphics inset.")
956 # If there's a inzip param, just remove that
957 k = find_token(document.body, "\tinzipName", i + 1, j)
960 # embed option must follow the inzipName option
961 del document.body[k+1]
965 def convert_inset_command(document):
968 \begin_inset LatexCommand cmd
970 \begin_inset CommandInset InsetType
975 i = find_token(document.body, "\\begin_inset LatexCommand", i)
978 line = document.body[i]
979 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
983 #this is adapted from factory.cpp
984 if cmdName[0:4].lower() == "cite":
985 insetName = "citation"
986 elif cmdName == "url" or cmdName == "htmlurl":
988 elif cmdName[-3:] == "ref":
990 elif cmdName == "tableofcontents":
992 elif cmdName == "printnomenclature":
993 insetName = "nomencl_print"
994 elif cmdName == "printindex":
995 insetName = "index_print"
998 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
999 document.body[i : i+1] = insertion
1002 def revert_inset_command(document):
1005 \begin_inset CommandInset InsetType
1008 \begin_inset LatexCommand cmd
1009 Some insets may end up being converted to insets earlier versions of LyX
1010 will not be able to recognize. Not sure what to do about that.
1014 i = find_token(document.body, "\\begin_inset CommandInset", i)
1017 nextline = document.body[i+1]
1018 r = re.compile(r'LatexCommand\s+(.*)$')
1019 m = r.match(nextline)
1021 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
1024 cmdName = m.group(1)
1025 insertion = ["\\begin_inset LatexCommand " + cmdName]
1026 document.body[i : i+2] = insertion
1029 def convert_wrapfig_options(document):
1030 "Convert optional options for wrap floats (wrapfig)."
1031 # adds the tokens "lines", "placement", and "overhang"
1034 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1037 document.body.insert(i + 1, "lines 0")
1038 j = find_token(document.body, "placement", i)
1039 # placement can be already set or not; if not, set it
1041 document.body.insert(i + 3, "overhang 0col%")
1043 document.body.insert(i + 2, "placement o")
1044 document.body.insert(i + 3, "overhang 0col%")
1048 def revert_wrapfig_options(document):
1049 "Revert optional options for wrap floats (wrapfig)."
1052 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1055 j = find_end_of_inset(document.body, i)
1057 document.warning("Can't find end of Wrap inset at line " + str(i))
1060 k = find_default_layout(document, i, j)
1062 document.warning("Can't find default layout for Wrap figure!")
1065 # Options should be between i and k now
1066 l = find_token(document.body, "lines", i, k)
1068 document.warning("Can't find lines option for Wrap figure!")
1071 m = find_token(document.body, "overhang", i + 1, k)
1073 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1076 # Do these in reverse order
1077 del document.body[m]
1078 del document.body[l]
1082 def convert_latexcommand_index(document):
1083 "Convert from LatexCommand form to collapsable form."
1085 r1 = re.compile('name "(.*)"')
1087 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1090 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1093 j = find_end_of_inset(document.body, i + 1)
1095 document.warning("Unable to find end of index inset at line " + str(i) + "!")
1098 m = r1.match(document.body[i + 2])
1100 document.warning("Unable to match: " + document.body[i+2])
1101 # this can happen with empty index insets!
1104 fullcontent = m.group(1)
1105 linelist = latex2lyx(fullcontent, True)
1106 #document.warning(fullcontent)
1108 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1109 linelist + ["\\end_layout"]
1110 document.body[i : j] = linelist
1111 i += len(linelist) - (j - i)
1114 def revert_latexcommand_index(document):
1115 "Revert from collapsable form to LatexCommand form."
1118 i = find_token(document.body, "\\begin_inset Index", i)
1121 j = find_end_of_inset(document.body, i + 1)
1125 content = lyx2latex(document, document.body[i:j])
1127 content = content.replace('"', r'\"')
1128 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1129 "name " + '"' + content + '"', ""]
1133 def revert_wraptable(document):
1134 "Revert wrap table to wrap figure."
1137 i = find_token(document.body, "\\begin_inset Wrap table", i)
1140 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1144 def revert_vietnamese(document):
1145 "Set language Vietnamese to English"
1146 # Set document language from Vietnamese to English
1148 if document.language == "vietnamese":
1149 document.language = "english"
1150 i = find_token(document.header, "\\language", 0)
1152 document.header[i] = "\\language english"
1155 j = find_token(document.body, "\\lang vietnamese", j)
1158 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1162 def convert_japanese_cjk(document):
1163 "Set language japanese to japanese-cjk"
1164 # Set document language from japanese-plain to japanese
1166 if document.language == "japanese":
1167 document.language = "japanese-cjk"
1168 i = find_token(document.header, "\\language", 0)
1170 document.header[i] = "\\language japanese-cjk"
1173 j = find_token(document.body, "\\lang japanese", j)
1176 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1180 def revert_japanese(document):
1181 "Set language japanese-plain to japanese"
1182 # Set document language from japanese-plain to japanese
1184 if document.language == "japanese-plain":
1185 document.language = "japanese"
1186 i = find_token(document.header, "\\language", 0)
1188 document.header[i] = "\\language japanese"
1191 j = find_token(document.body, "\\lang japanese-plain", j)
1194 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1198 def revert_japanese_cjk(document):
1199 "Set language japanese-cjk to japanese"
1200 # Set document language from japanese-plain to japanese
1202 if document.language == "japanese-cjk":
1203 document.language = "japanese"
1204 i = find_token(document.header, "\\language", 0)
1206 document.header[i] = "\\language japanese"
1209 j = find_token(document.body, "\\lang japanese-cjk", j)
1212 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1216 def revert_japanese_encoding(document):
1217 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1218 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1220 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1222 document.header[i] = "\\inputencoding EUC-JP"
1224 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1226 document.header[j] = "\\inputencoding JIS"
1228 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1229 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1230 document.header[k] = "\\inputencoding UTF8"
1233 def revert_inset_info(document):
1234 'Replace info inset with its content'
1237 i = find_token(document.body, '\\begin_inset Info', i)
1240 j = find_end_of_inset(document.body, i + 1)
1243 document.warning("Malformed LyX document: Could not find end of Info inset.")
1246 for k in range(i, j+1):
1247 if document.body[k].startswith("arg"):
1248 arg = document.body[k][3:].strip()
1249 # remove embracing quotation marks
1252 if arg[len(arg) - 1] == '"':
1253 arg = arg[:len(arg) - 1]
1254 # \" to straight quote
1255 arg = arg.replace(r'\"', '"')
1257 arg = arg.replace(r'\\', "\\backslash\n")
1258 if document.body[k].startswith("type"):
1259 type = document.body[k][4:].strip().strip('"')
1260 # I think there is a newline after \\end_inset, which should be removed.
1261 if document.body[j + 1].strip() == "":
1262 document.body[i : (j + 2)] = [type + ':' + arg]
1264 document.body[i : (j + 1)] = [type + ':' + arg]
1267 def convert_pdf_options(document):
1268 # Set the pdfusetitle tag, delete the pdf_store_options,
1269 # set quotes for bookmarksopenlevel"
1270 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1272 k = find_token(document.header, "\\use_hyperref", 0)
1273 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1274 k = find_token(document.header, "\\pdf_store_options", 0)
1276 del document.header[k]
1277 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1279 document.header[i] = document.header[i].replace('"', '')
1282 def revert_pdf_options_2(document):
1283 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1284 k = find_token(document.header, "\\use_hyperref", 0)
1285 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1287 del document.header[i]
1288 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1290 values = document.header[i].split()
1291 values[1] = ' "' + values[1] + '"'
1292 document.header[i] = ''.join(values)
1295 def convert_htmlurl(document):
1296 'Convert "htmlurl" to "href" insets for docbook'
1297 if document.backend != "docbook":
1301 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1304 document.body[i] = "\\begin_inset CommandInset href"
1305 document.body[i + 1] = "LatexCommand href"
1309 def convert_url(document):
1310 'Convert url insets to url charstyles'
1311 if document.backend == "docbook":
1315 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1318 n = find_token(document.body, "name", i)
1320 # place the URL name in typewriter before the new URL insert
1321 # grab the name 'bla' from the e.g. the line 'name "bla"',
1322 # therefore start with the 6th character
1323 name = document.body[n][6:-1]
1324 newname = [name + " "]
1325 document.body[i:i] = newname
1327 j = find_token(document.body, "target", i)
1329 document.warning("Malformed LyX document: Can't find target for url inset")
1332 target = document.body[j][8:-1]
1333 k = find_token(document.body, "\\end_inset", j)
1335 document.warning("Malformed LyX document: Can't find end of url inset")
1338 newstuff = ["\\begin_inset Flex URL",
1339 "status collapsed", "",
1340 "\\begin_layout Standard",
1345 document.body[i:k] = newstuff
1346 i = i + len(newstuff)
1348 def convert_ams_classes(document):
1349 tc = document.textclass
1350 if (tc != "amsart" and tc != "amsart-plain" and
1351 tc != "amsart-seq" and tc != "amsbook"):
1353 if tc == "amsart-plain":
1354 document.textclass = "amsart"
1355 document.set_textclass()
1356 document.add_module("Theorems (Starred)")
1358 if tc == "amsart-seq":
1359 document.textclass = "amsart"
1360 document.set_textclass()
1361 document.add_module("Theorems (AMS)")
1363 #Now we want to see if any of the environments in the extended theorems
1364 #module were used in this document. If so, we'll add that module, too.
1365 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1366 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1369 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1372 i = find_token(document.body, "\\begin_layout", i)
1375 m = r.match(document.body[i])
1377 # This is an empty layout
1378 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1382 if layouts.count(m) != 0:
1383 document.add_module("Theorems (AMS-Extended)")
1387 def revert_href(document):
1388 'Reverts hyperlink insets (href) to url insets (url)'
1391 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1394 document.body[i : i + 2] = \
1395 ["\\begin_inset CommandInset url", "LatexCommand url"]
1398 def revert_url(document):
1399 'Reverts Flex URL insets to old-style URL insets'
1402 i = find_token(document.body, "\\begin_inset Flex URL", i)
1405 j = find_end_of_inset(document.body, i)
1407 document.warning("Can't find end of inset in revert_url!")
1409 k = find_default_layout(document, i, j)
1411 document.warning("Can't find default layout in revert_url!")
1414 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1415 if l == -1 or l >= j:
1416 document.warning("Can't find end of default layout in revert_url!")
1419 # OK, so the inset's data is between lines k and l.
1420 data = " ".join(document.body[k+1:l])
1422 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1424 document.body[i:j+1] = newinset
1425 i = i + len(newinset)
1428 def convert_include(document):
1429 'Converts include insets to new format.'
1431 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1433 i = find_token(document.body, "\\begin_inset Include", i)
1436 line = document.body[i]
1437 previewline = document.body[i + 1]
1440 document.warning("Unable to match line " + str(i) + " of body!")
1446 insertion = ["\\begin_inset CommandInset include",
1447 "LatexCommand " + cmd, previewline,
1448 "filename \"" + fn + "\""]
1451 insertion.append("lstparams " + '"' + opt + '"')
1453 document.body[i : i + 2] = insertion
1457 def revert_include(document):
1458 'Reverts include insets to old format.'
1460 r0 = re.compile('preview.*')
1461 r1 = re.compile('LatexCommand (.+)')
1462 r2 = re.compile('filename "(.+)"')
1463 r3 = re.compile('lstparams "(.*)"')
1465 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1469 m = r1.match(document.body[nextline])
1471 document.warning("Malformed LyX document: No LatexCommand line for `" +
1472 document.body[i] + "' on line " + str(i) + ".")
1477 if r0.match(document.body[nextline]):
1478 previewline = document.body[nextline]
1482 m = r2.match(document.body[nextline])
1484 document.warning("Malformed LyX document: No filename line for `" + \
1485 document.body[i] + "' on line " + str(i) + ".")
1491 if (cmd == "lstinputlisting"):
1492 m = r3.match(document.body[nextline])
1494 options = m.group(1)
1497 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1499 newline += ("[" + options + "]")
1500 insertion = [newline]
1501 if previewline != "":
1502 insertion.append(previewline)
1503 document.body[i : nextline] = insertion
1507 def revert_albanian(document):
1508 "Set language Albanian to English"
1510 if document.language == "albanian":
1511 document.language = "english"
1512 i = find_token(document.header, "\\language", 0)
1514 document.header[i] = "\\language english"
1517 j = find_token(document.body, "\\lang albanian", j)
1520 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1524 def revert_lowersorbian(document):
1525 "Set language lower Sorbian to English"
1527 if document.language == "lowersorbian":
1528 document.language = "english"
1529 i = find_token(document.header, "\\language", 0)
1531 document.header[i] = "\\language english"
1534 j = find_token(document.body, "\\lang lowersorbian", j)
1537 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1541 def revert_uppersorbian(document):
1542 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1544 if document.language == "uppersorbian":
1545 document.language = "usorbian"
1546 i = find_token(document.header, "\\language", 0)
1548 document.header[i] = "\\language usorbian"
1551 j = find_token(document.body, "\\lang uppersorbian", j)
1554 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1558 def convert_usorbian(document):
1559 "Set language usorbian to uppersorbian"
1561 if document.language == "usorbian":
1562 document.language = "uppersorbian"
1563 i = find_token(document.header, "\\language", 0)
1565 document.header[i] = "\\language uppersorbian"
1568 j = find_token(document.body, "\\lang usorbian", j)
1571 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1575 def convert_macro_global(document):
1576 "Remove TeX code command \global when it is in front of a macro"
1577 # math macros are nowadays already defined \global, so that an additional
1578 # \global would make the document uncompilable, see
1579 # http://bugzilla.lyx.org/show_bug.cgi?id=5371
1580 # We're looking for something like this:
1584 # \begin_layout Plain Layout
1594 # \begin_inset FormulaMacro
1595 # \renewcommand{\foo}{123}
1599 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1602 # if i <= 13, then there isn't enough room for the ERT
1606 if document.body[i-6] == "global":
1607 del document.body[i-13 : i]
1613 def revert_macro_optional_params(document):
1614 "Convert macro definitions with optional parameters into ERTs"
1615 # Stub to convert macro definitions with one or more optional parameters
1616 # into uninterpreted ERT insets
1619 def revert_hyperlinktype(document):
1620 'Reverts hyperlink type'
1624 i = find_token(document.body, "target", i)
1627 j = find_token(document.body, "type", i)
1631 del document.body[j]
1635 def revert_pagebreak(document):
1636 'Reverts pagebreak to ERT'
1639 i = find_token(document.body, "\\pagebreak", i)
1642 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1643 '\\begin_layout Standard\n\n\n\\backslash\n' \
1644 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1648 def revert_linebreak(document):
1649 'Reverts linebreak to ERT'
1652 i = find_token(document.body, "\\linebreak", i)
1655 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1656 '\\begin_layout Standard\n\n\n\\backslash\n' \
1657 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1661 def revert_latin(document):
1662 "Set language Latin to English"
1664 if document.language == "latin":
1665 document.language = "english"
1666 i = find_token(document.header, "\\language", 0)
1668 document.header[i] = "\\language english"
1671 j = find_token(document.body, "\\lang latin", j)
1674 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1678 def revert_samin(document):
1679 "Set language North Sami to English"
1681 if document.language == "samin":
1682 document.language = "english"
1683 i = find_token(document.header, "\\language", 0)
1685 document.header[i] = "\\language english"
1688 j = find_token(document.body, "\\lang samin", j)
1691 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1695 def convert_serbocroatian(document):
1696 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1698 if document.language == "serbocroatian":
1699 document.language = "croatian"
1700 i = find_token(document.header, "\\language", 0)
1702 document.header[i] = "\\language croatian"
1705 j = find_token(document.body, "\\lang serbocroatian", j)
1708 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1712 def convert_framed_notes(document):
1713 "Convert framed notes to boxes. "
1716 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1719 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1728 'height_special "totalheight"']
1729 document.body[i:i+1] = subst
1733 def convert_module_names(document):
1734 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1735 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1736 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1737 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1738 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1739 modlist = document.get_module_list()
1740 if len(modlist) == 0:
1744 if modulemap.has_key(mod):
1745 newmodlist.append(modulemap[mod])
1747 document.warning("Can't find module %s in the module map!" % mod)
1748 newmodlist.append(mod)
1749 document.set_module_list(newmodlist)
1752 def revert_module_names(document):
1753 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1754 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1755 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1756 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1757 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1758 modlist = document.get_module_list()
1759 if len(modlist) == 0:
1763 if modulemap.has_key(mod):
1764 newmodlist.append(modulemap[mod])
1766 document.warning("Can't find module %s in the module map!" % mod)
1767 newmodlist.append(mod)
1768 document.set_module_list(newmodlist)
1771 def revert_colsep(document):
1772 i = find_token(document.header, "\\columnsep", 0)
1775 colsepline = document.header[i]
1776 r = re.compile(r'\\columnsep (.*)')
1777 m = r.match(colsepline)
1779 document.warning("Malformed column separation line!")
1782 del document.header[i]
1783 #it seems to be safe to add the package even if it is already used
1784 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1786 add_to_preamble(document, pretext)
1789 def revert_framed_notes(document):
1790 "Revert framed boxes to notes. "
1793 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1797 j = find_end_of_inset(document.body, i + 1)
1800 document.warning("Malformed LyX document: Could not find end of Box inset.")
1801 k = find_token(document.body, "status", i + 1, j)
1803 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1805 status = document.body[k]
1806 l = find_default_layout(document, i + 1, j)
1808 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1810 m = find_token(document.body, "\\end_layout", i + 1, j)
1812 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1814 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1815 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1816 if ibox == -1 and pbox == -1:
1817 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1818 del document.body[i+1:k]
1820 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1821 subst1 = [document.body[l],
1822 "\\begin_inset Note Shaded",
1824 '\\begin_layout Standard']
1825 document.body[l:l + 1] = subst1
1826 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1827 document.body[m:m + 1] = subst2
1831 def revert_slash(document):
1832 'Revert \\SpecialChar \\slash{} to ERT'
1834 while i < len(document.body):
1835 m = re.match(r'(.*)\\SpecialChar \\slash{}(.*)', document.body[i])
1840 '\\begin_inset ERT',
1841 'status collapsed', '',
1842 '\\begin_layout Standard',
1843 '', '', '\\backslash',
1848 document.body[i: i+1] = subst
1854 def revert_nobreakdash(document):
1855 'Revert \\SpecialChar \\nobreakdash- to ERT'
1857 while i < len(document.body):
1858 m = re.match(r'(.*)\\SpecialChar \\nobreakdash-(.*)', document.body[i])
1863 '\\begin_inset ERT',
1864 'status collapsed', '',
1865 '\\begin_layout Standard', '', '',
1871 document.body[i: i+1] = subst
1873 j = find_token(document.header, "\\use_amsmath", 0)
1875 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1877 document.header[j] = "\\use_amsmath 2"
1882 #Returns number of lines added/removed
1883 def revert_nocite_key(body, start, end):
1884 'key "..." -> \nocite{...}'
1885 r = re.compile(r'^key "(.*)"')
1889 m = r.match(body[i])
1891 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1892 j += 1 # because we added a line
1893 i += 2 # skip that line
1896 j -= 1 # because we deleted a line
1897 # no need to change i, since it now points to the next line
1901 def revert_nocite(document):
1902 "Revert LatexCommand nocite to ERT"
1905 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1908 if (document.body[i+1] != "LatexCommand nocite"):
1909 # note that we already incremented i
1912 insetEnd = find_end_of_inset(document.body, i)
1914 #this should not happen
1915 document.warning("End of CommandInset citation not found in revert_nocite!")
1918 paramLocation = i + 2 #start of the inset's parameters
1920 document.body[i:i+2] = \
1921 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1922 # that added two lines
1925 #print insetEnd, document.body[i: insetEnd + 1]
1926 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1927 #print insetEnd, document.body[i: insetEnd + 1]
1928 document.body.insert(insetEnd, "\\end_layout")
1929 document.body.insert(insetEnd + 1, "")
1933 def revert_btprintall(document):
1934 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1935 i = find_token(document.header, '\\use_bibtopic', 0)
1937 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1939 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1941 while i < len(document.body):
1942 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1945 j = find_end_of_inset(document.body, i + 1)
1947 #this should not happen
1948 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1949 j = len(document.body)
1950 # this range isn't really right, but it should be OK, since we shouldn't
1951 # see more than one matching line in each inset
1953 for k in range(i, j):
1954 if (document.body[k] == 'btprint "btPrintAll"'):
1955 del document.body[k]
1956 subst = ["\\begin_inset ERT",
1957 "status collapsed", "",
1958 "\\begin_layout Standard", "",
1963 document.body[i:i] = subst
1964 addlines = addedlines + len(subst) - 1
1968 def revert_bahasam(document):
1969 "Set language Bahasa Malaysia to Bahasa Indonesia"
1971 if document.language == "bahasam":
1972 document.language = "bahasa"
1973 i = find_token(document.header, "\\language", 0)
1975 document.header[i] = "\\language bahasa"
1978 j = find_token(document.body, "\\lang bahasam", j)
1981 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1985 def revert_interlingua(document):
1986 "Set language Interlingua to English"
1988 if document.language == "interlingua":
1989 document.language = "english"
1990 i = find_token(document.header, "\\language", 0)
1992 document.header[i] = "\\language english"
1995 j = find_token(document.body, "\\lang interlingua", j)
1998 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
2002 def revert_serbianlatin(document):
2003 "Set language Serbian-Latin to Croatian"
2005 if document.language == "serbian-latin":
2006 document.language = "croatian"
2007 i = find_token(document.header, "\\language", 0)
2009 document.header[i] = "\\language croatian"
2012 j = find_token(document.body, "\\lang serbian-latin", j)
2015 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
2019 def revert_rotfloat(document):
2020 " Revert sideways custom floats. "
2023 # whitespace intended (exclude \\begin_inset FloatList)
2024 i = find_token(document.body, "\\begin_inset Float ", i)
2027 line = document.body[i]
2028 r = re.compile(r'\\begin_inset Float (.*)$')
2031 document.warning("Unable to match line " + str(i) + " of body!")
2034 floattype = m.group(1)
2035 if floattype == "figure" or floattype == "table":
2038 j = find_end_of_inset(document.body, i)
2040 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
2044 if get_value(document.body, 'sideways', i, j) == "false":
2047 l = find_default_layout(document, i + 1, j)
2049 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2051 subst = ['\\begin_layout Standard',
2052 '\\begin_inset ERT',
2053 'status collapsed', '',
2054 '\\begin_layout Standard', '', '',
2056 'end{sideways' + floattype + '}',
2057 '\\end_layout', '', '\\end_inset']
2058 document.body[j : j+1] = subst
2059 addedLines = len(subst) - 1
2060 del document.body[i+1 : l]
2061 addedLines -= (l-1) - (i+1)
2062 subst = ['\\begin_inset ERT', 'status collapsed', '',
2063 '\\begin_layout Standard', '', '', '\\backslash',
2064 'begin{sideways' + floattype + '}',
2065 '\\end_layout', '', '\\end_inset', '',
2067 document.body[i : i+1] = subst
2068 addedLines += len(subst) - 1
2069 if floattype == "algorithm":
2070 add_to_preamble(document,
2071 ['% Commands inserted by lyx2lyx for sideways algorithm float',
2072 '\\usepackage{rotfloat}',
2073 '\\floatstyle{ruled}',
2074 '\\newfloat{algorithm}{tbp}{loa}',
2075 '\\floatname{algorithm}{Algorithm}'])
2077 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
2081 def revert_widesideways(document):
2082 " Revert wide sideways floats. "
2085 # whitespace intended (exclude \\begin_inset FloatList)
2086 i = find_token(document.body, '\\begin_inset Float ', i)
2089 line = document.body[i]
2090 r = re.compile(r'\\begin_inset Float (.*)$')
2093 document.warning("Unable to match line " + str(i) + " of body!")
2096 floattype = m.group(1)
2097 if floattype != "figure" and floattype != "table":
2100 j = find_end_of_inset(document.body, i)
2102 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2105 if get_value(document.body, 'sideways', i, j) == "false" or \
2106 get_value(document.body, 'wide', i, j) == "false":
2109 l = find_default_layout(document, i + 1, j)
2111 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2113 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2114 'status collapsed', '',
2115 '\\begin_layout Standard', '', '', '\\backslash',
2116 'end{sideways' + floattype + '*}',
2117 '\\end_layout', '', '\\end_inset']
2118 document.body[j : j+1] = subst
2119 addedLines = len(subst) - 1
2120 del document.body[i+1:l-1]
2121 addedLines -= (l-1) - (i+1)
2122 subst = ['\\begin_inset ERT', 'status collapsed', '',
2123 '\\begin_layout Standard', '', '', '\\backslash',
2124 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2125 '\\end_inset', '', '\\end_layout', '']
2126 document.body[i : i+1] = subst
2127 addedLines += len(subst) - 1
2128 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2132 def revert_inset_embedding(document, type):
2133 ' Remove embed tag from certain type of insets'
2136 i = find_token(document.body, "\\begin_inset %s" % type, i)
2139 j = find_end_of_inset(document.body, i)
2141 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2144 k = find_token(document.body, "\tembed", i, j)
2146 k = find_token(document.body, "embed", i, j)
2148 del document.body[k]
2152 def revert_external_embedding(document):
2153 ' Remove embed tag from external inset '
2154 revert_inset_embedding(document, 'External')
2157 def convert_subfig(document):
2158 " Convert subfigures to subfloats. "
2162 i = find_token(document.body, '\\begin_inset Graphics', i)
2165 endInset = find_end_of_inset(document.body, i)
2167 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2170 k = find_token(document.body, '\tsubcaption', i, endInset)
2174 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2178 caption = document.body[l][16:].strip('"')
2179 del document.body[l]
2181 del document.body[k]
2183 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2184 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2185 '', '\\begin_layout Plain Layout'] + latex2lyx(caption, False) + \
2186 [ '\\end_layout', '', '\\end_inset', '',
2187 '\\end_layout', '', '\\begin_layout Plain Layout']
2188 document.body[i : i] = subst
2189 addedLines += len(subst)
2190 endInset += addedLines
2191 subst = ['', '\\end_inset', '', '\\end_layout']
2192 document.body[endInset : endInset] = subst
2193 addedLines += len(subst)
2197 def revert_subfig(document):
2198 " Revert subfloats. "
2201 # whitespace intended (exclude \\begin_inset FloatList)
2202 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2208 j = find_end_of_inset(document.body, i)
2210 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2211 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2213 continue # this will get us back to the outer loop, since j == -1
2214 # look for embedded float (= subfloat)
2215 # whitespace intended (exclude \\begin_inset FloatList)
2216 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2219 # is the subfloat aligned?
2220 al = find_token(document.body, '\\align ', k - 1, j)
2224 if get_value(document.body, '\\align', al) == "center":
2225 alignment_beg = "\\backslash\nbegin{centering}"
2226 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2227 elif get_value(document.body, '\\align', al) == "left":
2228 alignment_beg = "\\backslash\nbegin{raggedright}"
2229 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2230 elif get_value(document.body, '\\align', al) == "right":
2231 alignment_beg = "\\backslash\nbegin{raggedleft}"
2232 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2233 l = find_end_of_inset(document.body, k)
2235 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2238 continue # escape to the outer loop
2239 m = find_default_layout(document, k + 1, l)
2241 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2246 capend = find_end_of_inset(document.body, cap)
2248 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2252 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2254 lblend = find_end_of_inset(document.body, lbl + 1)
2256 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2258 for line in document.body[lbl:lblend + 1]:
2259 if line.startswith('name '):
2260 label = line.split()[1].strip('"')
2267 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2269 optend = find_end_of_inset(document.body, opt)
2271 document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
2273 optc = find_default_layout(document, opt, optend)
2275 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2277 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2278 for line in document.body[optc:optcend]:
2279 if not line.startswith('\\'):
2280 shortcap += line.strip()
2284 for line in document.body[cap:capend]:
2285 if line in document.body[lbl:lblend]:
2287 elif line in document.body[opt:optend]:
2291 caption += lyxline2latex(document, line, inert)
2293 caption += "\n\\backslash\nlabel{" + label + "}"
2294 subst = '\\begin_layout PlainLayout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2295 '\\begin_layout PlainLayout\n\n}' + alignment_end + \
2296 '\n\\end_layout\n\n\\end_inset\n\n' \
2297 '\\end_layout\n\n\\begin_layout PlainLayout\n'
2298 subst = subst.split('\n')
2299 document.body[l : l+1] = subst
2300 addedLines = len(subst) - 1
2301 # this is before l and so is unchanged by the multiline insertion
2303 del document.body[cap:capend+1]
2304 addedLines -= (capend + 1 - cap)
2305 del document.body[k+1:m-1]
2306 addedLines -= (m - 1 - (k + 1))
2307 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2308 '\\begin_layout PlainLayout\n\n' + alignment_beg + '\n\\backslash\n' \
2310 if len(shortcap) > 0:
2311 insertion = insertion + "[" + shortcap + "]"
2312 if len(caption) > 0:
2313 insertion = insertion + "[" + caption + "]"
2314 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2315 insertion = insertion.split('\n')
2316 document.body[k : k + 1] = insertion
2317 addedLines += len(insertion) - 1
2318 al = find_token(document.body, '\\align ', k - 1, j + addedLines)
2320 del document.body[al]
2322 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2326 def revert_wrapplacement(document):
2327 " Revert placement options wrap floats (wrapfig). "
2330 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2333 e = find_end_of_inset(document.body, i)
2334 j = find_token(document.body, "placement", i + 1, e)
2336 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2339 r = re.compile("placement (o|i|l|r|O|I|L|R)")
2340 m = r.match(document.body[j])
2342 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2344 document.body[j] = "placement " + m.group(1).lower()
2348 def remove_extra_embedded_files(document):
2349 " Remove \extra_embedded_files from buffer params "
2350 i = find_token(document.header, '\\extra_embedded_files', 0)
2353 document.header.pop(i)
2356 def convert_spaceinset(document):
2357 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2359 while i < len(document.body):
2360 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2364 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2365 document.body[i: i+1] = subst
2371 def revert_spaceinset(document):
2372 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2375 i = find_token(document.body, "\\begin_inset Space", i)
2378 j = find_end_of_inset(document.body, i)
2380 document.warning("Malformed LyX document: Could not find end of space inset.")
2382 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2383 del document.body[j]
2386 def convert_hfill(document):
2387 " Convert hfill to space inset "
2390 i = find_token(document.body, "\\hfill", i)
2393 subst = document.body[i].replace('\\hfill', \
2394 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2395 subst = subst.split('\n')
2396 document.body[i : i+1] = subst
2400 def revert_hfills(document):
2401 ' Revert \\hfill commands '
2402 hfill = re.compile(r'\\hfill')
2403 dotfill = re.compile(r'\\dotfill')
2404 hrulefill = re.compile(r'\\hrulefill')
2407 i = find_token(document.body, "\\InsetSpace", i)
2410 if hfill.search(document.body[i]):
2411 document.body[i] = \
2412 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2415 if dotfill.search(document.body[i]):
2416 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2417 '\\begin_inset ERT\nstatus collapsed\n\n' \
2418 '\\begin_layout Standard\n\n\n\\backslash\n' \
2419 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2420 subst = subst.split('\n')
2421 document.body[i : i+1] = subst
2424 if hrulefill.search(document.body[i]):
2425 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2426 '\\begin_inset ERT\nstatus collapsed\n\n' \
2427 '\\begin_layout Standard\n\n\n\\backslash\n' \
2428 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2429 subst = subst.split('\n')
2430 document.body[i : i+1] = subst
2435 def revert_hspace(document):
2436 ' Revert \\InsetSpace \\hspace{} to ERT '
2438 hspace = re.compile(r'\\hspace{}')
2439 hstar = re.compile(r'\\hspace\*{}')
2441 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2444 length = get_value(document.body, '\\length', i+1)
2446 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2448 del document.body[i+1]
2450 if hstar.search(document.body[i]):
2451 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2452 '\\begin_inset ERT\nstatus collapsed\n\n' \
2453 '\\begin_layout Standard\n\n\n\\backslash\n' \
2454 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2455 subst = subst.split('\n')
2456 document.body[i : i+1] = subst
2457 addedLines += len(subst) - 1
2460 if hspace.search(document.body[i]):
2461 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2462 '\\begin_inset ERT\nstatus collapsed\n\n' \
2463 '\\begin_layout Standard\n\n\n\\backslash\n' \
2464 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2465 subst = subst.split('\n')
2466 document.body[i : i+1] = subst
2467 addedLines += len(subst) - 1
2473 def revert_protected_hfill(document):
2474 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2477 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2480 j = find_end_of_inset(document.body, i)
2482 document.warning("Malformed LyX document: Could not find end of space inset.")
2484 del document.body[j]
2485 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2486 '\\begin_inset ERT\nstatus collapsed\n\n' \
2487 '\\begin_layout Standard\n\n\n\\backslash\n' \
2488 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2489 subst = subst.split('\n')
2490 document.body[i : i+1] = subst
2494 def revert_leftarrowfill(document):
2495 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2498 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2501 j = find_end_of_inset(document.body, i)
2503 document.warning("Malformed LyX document: Could not find end of space inset.")
2505 del document.body[j]
2506 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2507 '\\begin_inset ERT\nstatus collapsed\n\n' \
2508 '\\begin_layout Standard\n\n\n\\backslash\n' \
2509 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2510 subst = subst.split('\n')
2511 document.body[i : i+1] = subst
2515 def revert_rightarrowfill(document):
2516 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2519 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2522 j = find_end_of_inset(document.body, i)
2524 document.warning("Malformed LyX document: Could not find end of space inset.")
2526 del document.body[j]
2527 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2528 '\\begin_inset ERT\nstatus collapsed\n\n' \
2529 '\\begin_layout Standard\n\n\n\\backslash\n' \
2530 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2531 subst = subst.split('\n')
2532 document.body[i : i+1] = subst
2536 def revert_upbracefill(document):
2537 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2540 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2543 j = find_end_of_inset(document.body, i)
2545 document.warning("Malformed LyX document: Could not find end of space inset.")
2547 del document.body[j]
2548 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2549 '\\begin_inset ERT\nstatus collapsed\n\n' \
2550 '\\begin_layout Standard\n\n\n\\backslash\n' \
2551 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2552 subst = subst.split('\n')
2553 document.body[i : i+1] = subst
2557 def revert_downbracefill(document):
2558 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2561 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2564 j = find_end_of_inset(document.body, i)
2566 document.warning("Malformed LyX document: Could not find end of space inset.")
2568 del document.body[j]
2569 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2570 '\\begin_inset ERT\nstatus collapsed\n\n' \
2571 '\\begin_layout Standard\n\n\n\\backslash\n' \
2572 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2573 subst = subst.split('\n')
2574 document.body[i : i+1] = subst
2578 def revert_local_layout(document):
2579 ' Revert local layout headers.'
2582 i = find_token(document.header, "\\begin_local_layout", i)
2585 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2587 # this should not happen
2589 document.header[i : j + 1] = []
2592 def convert_pagebreaks(document):
2593 ' Convert inline Newpage insets to new format '
2596 i = find_token(document.body, '\\newpage', i)
2599 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2603 i = find_token(document.body, '\\pagebreak', i)
2606 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2610 i = find_token(document.body, '\\clearpage', i)
2613 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2617 i = find_token(document.body, '\\cleardoublepage', i)
2620 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2624 def revert_pagebreaks(document):
2625 ' Revert \\begin_inset Newpage to previous inline format '
2628 i = find_token(document.body, '\\begin_inset Newpage', i)
2631 j = find_end_of_inset(document.body, i)
2633 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.")
2671 del document.body[j]
2672 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2673 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2676 def convert_japanese_plain(document):
2677 ' Set language japanese-plain to japanese '
2679 if document.language == "japanese-plain":
2680 document.language = "japanese"
2681 i = find_token(document.header, "\\language", 0)
2683 document.header[i] = "\\language japanese"
2686 j = find_token(document.body, "\\lang japanese-plain", j)
2689 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2693 def revert_pdfpages(document):
2694 ' Revert pdfpages external inset to ERT '
2697 i = find_token(document.body, "\\begin_inset External", i)
2700 j = find_end_of_inset(document.body, i)
2702 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2705 if get_value(document.body, 'template', i, j) == "PDFPages":
2706 filename = get_value(document.body, 'filename', i, j)
2708 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2709 for k in range(i, j):
2710 m = r.match(document.body[k])
2713 angle = get_value(document.body, 'rotateAngle', i, j)
2714 width = get_value(document.body, 'width', i, j)
2715 height = get_value(document.body, 'height', i, j)
2716 scale = get_value(document.body, 'scale', i, j)
2717 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2721 options += ",angle=" + angle
2723 options += "angle=" + angle
2726 options += ",width=" + convert_len(width)
2728 options += "width=" + convert_len(width)
2731 options += ",height=" + convert_len(height)
2733 options += "height=" + convert_len(height)
2736 options += ",scale=" + scale
2738 options += "scale=" + scale
2739 if keepAspectRatio != '':
2741 options += ",keepaspectratio"
2743 options += "keepaspectratio"
2745 options = '[' + options + ']'
2746 del document.body[i+1:j+1]
2747 document.body[i:i+1] = ['\\begin_inset ERT',
2750 '\\begin_layout Standard',
2753 'includepdf' + options + '{' + filename + '}',
2757 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2763 def revert_mexican(document):
2764 ' Set language Spanish(Mexico) to Spanish '
2766 if document.language == "spanish-mexico":
2767 document.language = "spanish"
2768 i = find_token(document.header, "\\language", 0)
2770 document.header[i] = "\\language spanish"
2773 j = find_token(document.body, "\\lang spanish-mexico", j)
2776 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2780 def remove_embedding(document):
2781 ' Remove embed tag from all insets '
2782 revert_inset_embedding(document, 'Graphics')
2783 revert_inset_embedding(document, 'External')
2784 revert_inset_embedding(document, 'CommandInset include')
2785 revert_inset_embedding(document, 'CommandInset bibtex')
2788 def revert_master(document):
2789 ' Remove master param '
2790 i = find_token(document.header, "\\master", 0)
2792 del document.header[i]
2795 def revert_graphics_group(document):
2796 ' Revert group information from graphics insets '
2799 i = find_token(document.body, "\\begin_inset Graphics", i)
2802 j = find_end_of_inset(document.body, i)
2804 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2807 k = find_token(document.body, " groupId", i, j)
2811 del document.body[k]
2815 def update_apa_styles(document):
2816 ' Replace obsolete styles '
2818 if document.textclass != "apa":
2821 obsoletedby = { "Acknowledgments": "Acknowledgements",
2822 "Section*": "Section",
2823 "Subsection*": "Subsection",
2824 "Subsubsection*": "Subsubsection",
2825 "Paragraph*": "Paragraph",
2826 "Subparagraph*": "Subparagraph"}
2829 i = find_token(document.body, "\\begin_layout", i)
2833 layout = document.body[i][14:]
2834 if layout in obsoletedby:
2835 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2840 def convert_paper_sizes(document):
2841 ' exchange size options legalpaper and executivepaper to correct order '
2842 # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2845 i = find_token(document.header, "\\papersize executivepaper", 0)
2847 document.header[i] = "\\papersize legalpaper"
2849 j = find_token(document.header, "\\papersize legalpaper", 0)
2851 document.header[j] = "\\papersize executivepaper"
2854 def revert_paper_sizes(document):
2855 ' exchange size options legalpaper and executivepaper to correct order '
2858 i = find_token(document.header, "\\papersize executivepaper", 0)
2860 document.header[i] = "\\papersize legalpaper"
2862 j = find_token(document.header, "\\papersize legalpaper", 0)
2864 document.header[j] = "\\papersize executivepaper"
2867 def convert_InsetSpace(document):
2868 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2871 i = find_token(document.body, "\\begin_inset Space", i)
2874 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2877 def revert_InsetSpace(document):
2878 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2881 i = find_token(document.body, "\\begin_inset space", i)
2884 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2887 def convert_display_enum(document):
2888 " Convert 'display foo' to 'display false/true'"
2891 i = find_token(document.body, "\tdisplay", i)
2894 val = get_value(document.body, 'display', i)
2896 document.body[i] = document.body[i].replace('none', 'false')
2897 if val == "default":
2898 document.body[i] = document.body[i].replace('default', 'true')
2899 if val == "monochrome":
2900 document.body[i] = document.body[i].replace('monochrome', 'true')
2901 if val == "grayscale":
2902 document.body[i] = document.body[i].replace('grayscale', 'true')
2904 document.body[i] = document.body[i].replace('color', 'true')
2905 if val == "preview":
2906 document.body[i] = document.body[i].replace('preview', 'true')
2910 def revert_display_enum(document):
2911 " Revert 'display false/true' to 'display none/color'"
2914 i = find_token(document.body, "\tdisplay", i)
2917 val = get_value(document.body, 'display', i)
2919 document.body[i] = document.body[i].replace('false', 'none')
2921 document.body[i] = document.body[i].replace('true', 'default')
2925 def remove_fontsCJK(document):
2926 ' Remove font_cjk param '
2927 i = find_token(document.header, "\\font_cjk", 0)
2929 del document.header[i]
2932 def convert_plain_layout(document):
2933 " Convert 'PlainLayout' to 'Plain Layout'"
2936 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2939 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2940 '\\begin_layout Plain Layout')
2944 def revert_plain_layout(document):
2945 " Revert 'Plain Layout' to 'PlainLayout'"
2948 i = find_token(document.body, '\\begin_layout Plain Layout', i)
2951 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2952 '\\begin_layout PlainLayout')
2956 def revert_plainlayout(document):
2957 " Revert 'PlainLayout' to 'Standard'"
2960 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2963 # This will be incorrect for some document classes, since Standard is not always
2964 # the default. But (a) it is probably the best we can do and (b) it will actually
2965 # work, in fact, since an unknown layout will be converted to default.
2966 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2967 '\\begin_layout Standard')
2971 def revert_polytonicgreek(document):
2972 "Set language polytonic Greek to Greek"
2974 if document.language == "polutonikogreek":
2975 document.language = "greek"
2976 i = find_token(document.header, "\\language", 0)
2978 document.header[i] = "\\language greek"
2981 j = find_token(document.body, "\\lang polutonikogreek", j)
2984 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2988 def revert_removed_modules(document):
2991 i = find_token(document.header, "\\begin_remove_modules", i)
2994 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
2996 # this should not happen
2998 document.header[i : j + 1] = []
3001 def add_plain_layout(document):
3004 i = find_token(document.body, "\\begin_layout", i)
3007 if len(document.body[i].split()) == 1:
3008 document.body[i] = "\\begin_layout Plain Layout"
3012 def revert_tabulators(document):
3013 "Revert tabulators to 4 spaces"
3016 i = find_token(document.body, "\t", i)
3019 document.body[i] = document.body[i].replace("\t", " ")
3023 def revert_tabsize(document):
3024 "Revert the tabsize parameter of listings"
3028 # either it is the only parameter
3029 i = find_token(document.body, 'lstparams "tabsize=4"', i)
3031 del document.body[i]
3033 j = find_token(document.body, "lstparams", j)
3036 pos = document.body[j].find(",tabsize=")
3037 document.body[j] = document.body[j][:pos] + '"'
3042 def revert_mongolian(document):
3043 "Set language Mongolian to English"
3045 if document.language == "mongolian":
3046 document.language = "english"
3047 i = find_token(document.header, "\\language", 0)
3049 document.header[i] = "\\language english"
3052 j = find_token(document.body, "\\lang mongolian", j)
3055 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
3059 def revert_default_options(document):
3060 ' Remove param use_default_options '
3061 i = find_token(document.header, "\\use_default_options", 0)
3063 del document.header[i]
3066 def convert_default_options(document):
3067 ' Add param use_default_options and set it to false '
3068 i = find_token(document.header, "\\textclass", 0)
3070 document.warning("Malformed LyX document: Missing `\\textclass'.")
3072 document.header.insert(i, '\\use_default_options false')
3075 def revert_backref_options(document):
3076 ' Revert option pdf_backref=page to pagebackref '
3077 i = find_token(document.header, "\\pdf_backref page", 0)
3079 document.header[i] = "\\pdf_pagebackref true"
3082 def convert_backref_options(document):
3083 ' We have changed the option pagebackref to backref=true '
3084 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3086 document.header[i] = "\\pdf_backref page"
3087 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3089 del document.header[j]
3090 # backref=true was not a valid option, we meant backref=section
3091 k = find_token(document.header, "\\pdf_backref true", 0)
3092 if k != -1 and i != -1:
3093 del document.header[k]
3094 elif k != -1 and j != -1:
3095 document.header[k] = "\\pdf_backref section"
3098 def convert_charstyle_element(document):
3099 "Convert CharStyle to Element for docbook backend"
3100 if document.backend != "docbook":
3104 i = find_token(document.body, "\\begin_inset Flex CharStyle:", i)
3107 document.body[i] = document.body[i].replace('\\begin_inset Flex CharStyle:',
3108 '\\begin_inset Flex Element:')
3110 def revert_charstyle_element(document):
3111 "Convert Element to CharStyle for docbook backend"
3112 if document.backend != "docbook":
3116 i = find_token(document.body, "\\begin_inset Flex Element:", i)
3119 document.body[i] = document.body[i].replace('\\begin_inset Flex Element:',
3120 '\\begin_inset Flex CharStyle:')
3126 supported_versions = ["1.6.0","1.6"]
3127 convert = [[277, [fix_wrong_tables]],
3128 [278, [close_begin_deeper]],
3129 [279, [long_charstyle_names]],
3130 [280, [axe_show_label]],
3133 [283, [convert_flex]],
3137 [287, [convert_wrapfig_options]],
3138 [288, [convert_inset_command]],
3139 [289, [convert_latexcommand_index]],
3142 [292, [convert_japanese_cjk]],
3144 [294, [convert_pdf_options]],
3145 [295, [convert_htmlurl, convert_url]],
3146 [296, [convert_include]],
3147 [297, [convert_usorbian]],
3148 [298, [convert_macro_global]],
3153 [303, [convert_serbocroatian]],
3154 [304, [convert_framed_notes]],
3161 [311, [convert_ams_classes]],
3163 [313, [convert_module_names]],
3166 [316, [convert_subfig]],
3169 [319, [convert_spaceinset, convert_hfill]],
3171 [321, [convert_tablines]],
3172 [322, [convert_plain_layout]],
3173 [323, [convert_pagebreaks]],
3174 [324, [convert_linebreaks]],
3175 [325, [convert_japanese_plain]],
3178 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3181 [331, [convert_ltcaption]],
3183 [333, [update_apa_styles]],
3184 [334, [convert_paper_sizes]],
3185 [335, [convert_InsetSpace]],
3187 [337, [convert_display_enum]],
3190 [340, [add_plain_layout]],
3193 [343, [convert_default_options]],
3194 [344, [convert_backref_options]],
3195 [345, [convert_charstyle_element]]
3198 revert = [[344, [revert_charstyle_element]],
3199 [343, [revert_backref_options]],
3200 [342, [revert_default_options]],
3201 [341, [revert_mongolian]],
3202 [340, [revert_tabulators, revert_tabsize]],
3204 [338, [revert_removed_modules]],
3205 [337, [revert_polytonicgreek]],
3206 [336, [revert_display_enum]],
3207 [335, [remove_fontsCJK]],
3208 [334, [revert_InsetSpace]],
3209 [333, [revert_paper_sizes]],
3211 [331, [revert_graphics_group]],
3212 [330, [revert_ltcaption]],
3213 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
3214 [328, [revert_master]],
3216 [326, [revert_mexican]],
3217 [325, [revert_pdfpages]],
3219 [323, [revert_linebreaks]],
3220 [322, [revert_pagebreaks]],
3221 [321, [revert_local_layout, revert_plain_layout]],
3222 [320, [revert_tablines]],
3223 [319, [revert_protected_hfill]],
3224 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3225 [317, [remove_extra_embedded_files]],
3226 [316, [revert_wrapplacement]],
3227 [315, [revert_subfig]],
3228 [314, [revert_colsep, revert_plainlayout]],
3230 [312, [revert_module_names]],
3231 [311, [revert_rotfloat, revert_widesideways]],
3232 [310, [revert_external_embedding]],
3233 [309, [revert_btprintall]],
3234 [308, [revert_nocite]],
3235 [307, [revert_serbianlatin]],
3236 [306, [revert_slash, revert_nobreakdash]],
3237 [305, [revert_interlingua]],
3238 [304, [revert_bahasam]],
3239 [303, [revert_framed_notes]],
3241 [301, [revert_latin, revert_samin]],
3242 [300, [revert_linebreak]],
3243 [299, [revert_pagebreak]],
3244 [298, [revert_hyperlinktype]],
3245 [297, [revert_macro_optional_params]],
3246 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3247 [295, [revert_include]],
3248 [294, [revert_href, revert_url]],
3249 [293, [revert_pdf_options_2]],
3250 [292, [revert_inset_info]],
3251 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3252 [290, [revert_vietnamese]],
3253 [289, [revert_wraptable]],
3254 [288, [revert_latexcommand_index]],
3255 [287, [revert_inset_command]],
3256 [286, [revert_wrapfig_options]],
3257 [285, [revert_pdf_options]],
3258 [284, [remove_inzip_options]],
3260 [282, [revert_flex]],
3262 [280, [revert_begin_modules]],
3263 [279, [revert_show_label]],
3264 [278, [revert_long_charstyle_names]],
3270 if __name__ == "__main__":