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:])
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, '{', '{')
253 unicode_reps = read_unicodesymbols()
256 #Might should do latex2ert first, then deal with stuff that DOESN'T
257 #end up inside ERT. That routine could be modified so that it returned
258 #a list of lines, and we could then skip ERT bits and only deal with
261 '''Takes a string, possibly multi-line, and returns the result of
262 converting LaTeX constructs into LyX constructs. Returns a list of
263 lines, suitable for insertion into document.body.'''
269 # Convert LaTeX to Unicode
270 # Commands of this sort need to be checked to make sure they are
271 # followed by a non-alpha character, lest we replace too much.
272 hardone = re.compile(r'^\\\\[a-zA-Z]+$')
274 for rep in unicode_reps:
275 if hardone.match(rep[0]):
278 pos = data.find(rep[0], pos)
281 nextpos = pos + len(rep[0])
282 if nextpos < len(data) and data[nextpos].isalpha():
283 # not the end of that command
286 data = data[:pos] + rep[1] + data[nextpos:]
289 data = data.replace(rep[0], rep[1])
293 data = wrap_into_ert(data, r'\"', '"')
295 data = data.replace('\\\\', '\\')
298 mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
299 lines = data.split('\n')
301 #document.warning("LINE: " + line)
302 #document.warning(str(i) + ":" + document.body[i])
303 #document.warning("LAST: " + document.body[-1])
308 f = m.group(2).replace('\\\\', '\\')
313 subst = s.split('\n')
315 retval.append("\\begin_inset Formula " + f)
316 retval.append("\\end_inset")
318 # Handle whatever is left, which is just text
320 subst = g.split('\n')
325 def lyx2latex(document, lines):
326 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
327 # clean up multiline stuff
331 for curline in range(len(lines)):
332 line = lines[curline]
333 if line.startswith("\\begin_inset ERT"):
334 # We don't want to replace things inside ERT, so figure out
335 # where the end of the inset is.
336 ert_end = find_end_of_inset(lines, curline + 1)
338 elif line.startswith("\\begin_inset Formula"):
340 elif line.startswith("\\begin_inset Quotes"):
341 # For now, we do a very basic reversion. Someone who understands
342 # quotes is welcome to fix it up.
343 qtype = line[20:].strip()
357 elif line.isspace() or \
358 line.startswith("\\begin_layout") or \
359 line.startswith("\\end_layout") or \
360 line.startswith("\\begin_inset") or \
361 line.startswith("\\end_inset") or \
362 line.startswith("\\lang") or \
363 line.strip() == "status collapsed" or \
364 line.strip() == "status open":
368 # this needs to be added to the preamble because of cases like
369 # \textmu, \textbackslash, etc.
370 add_to_preamble(document, ['% added by lyx2lyx for converted index entries',
371 '\\@ifundefined{textmu}',
372 ' {\\usepackage{textcomp}}{}'])
373 # a lossless reversion is not possible
374 # try at least to handle some common insets and settings
375 if ert_end >= curline:
376 line = line.replace(r'\backslash', r'\\')
378 line = line.replace('&', '\\&{}')
379 line = line.replace('#', '\\#{}')
380 line = line.replace('^', '\\^{}')
381 line = line.replace('%', '\\%{}')
382 line = line.replace('_', '\\_{}')
383 line = line.replace('$', '\\${}')
385 # Do the LyX text --> LaTeX conversion
386 for rep in unicode_reps:
387 line = line.replace(rep[1], rep[0] + "{}")
388 line = line.replace(r'\backslash', r'\textbackslash{}')
389 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
390 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
391 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
392 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
393 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
394 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
395 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
396 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
397 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
402 ####################################################################
404 def convert_ltcaption(document):
407 i = find_token(document.body, "\\begin_inset Tabular", i)
410 j = find_end_of_inset(document.body, i + 1)
412 document.warning("Malformed LyX document: Could not find end of tabular.")
415 nrows = int(document.body[i+1].split('"')[3])
416 ncols = int(document.body[i+1].split('"')[5])
419 for k in range(nrows):
420 m = find_token(document.body, "<row", m)
423 for k in range(ncols):
424 m = find_token(document.body, "<cell", m)
426 mend = find_token(document.body, "</cell>", m + 1)
427 # first look for caption insets
428 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
429 # then look for ERT captions
431 mcap = find_token(document.body, "caption", m + 1, mend)
433 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
436 if caption == 'true':
438 set_option(document, r, 'caption', 'true')
439 set_option(document, m, 'multicolumn', '1')
440 set_option(document, m, 'bottomline', 'false')
441 set_option(document, m, 'topline', 'false')
442 set_option(document, m, 'rightline', 'false')
443 set_option(document, m, 'leftline', 'false')
444 #j = find_end_of_inset(document.body, j + 1)
446 set_option(document, m, 'multicolumn', '2')
453 #FIXME Use of wrap_into_ert can confuse lyx2lyx
454 def revert_ltcaption(document):
457 i = find_token(document.body, "\\begin_inset Tabular", i)
460 j = find_end_of_inset(document.body, i + 1)
462 document.warning("Malformed LyX document: Could not find end of tabular.")
466 nrows = int(document.body[i+1].split('"')[3])
467 ncols = int(document.body[i+1].split('"')[5])
469 for k in range(nrows):
470 m = find_token(document.body, "<row", m)
471 caption = get_option(document, m, 'caption', 'false')
472 if caption == 'true':
473 remove_option(document, m, 'caption')
474 for k in range(ncols):
475 m = find_token(document.body, "<cell", m)
476 remove_option(document, m, 'multicolumn')
478 m = find_token(document.body, "\\begin_inset Caption", m)
481 m = find_end_of_inset(document.body, m + 1)
482 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
488 def convert_tablines(document):
491 i = find_token(document.body, "\\begin_inset Tabular", i)
493 # LyX 1.3 inserted an extra space between \begin_inset
494 # and Tabular so let us try if this is the case and fix it.
495 i = find_token(document.body, "\\begin_inset Tabular", i)
499 document.body[i] = "\\begin_inset Tabular"
500 j = find_end_of_inset(document.body, i + 1)
502 document.warning("Malformed LyX document: Could not find end of tabular.")
506 nrows = int(document.body[i+1].split('"')[3])
507 ncols = int(document.body[i+1].split('"')[5])
510 for k in range(ncols):
511 m = find_token(document.body, "<column", m)
512 left = get_option(document, m, 'leftline', 'false')
513 right = get_option(document, m, 'rightline', 'false')
514 col_info.append([left, right])
515 remove_option(document, m, 'leftline')
516 remove_option(document, m, 'rightline')
520 for k in range(nrows):
521 m = find_token(document.body, "<row", m)
522 top = get_option(document, m, 'topline', 'false')
523 bottom = get_option(document, m, 'bottomline', 'false')
524 row_info.append([top, bottom])
525 remove_option(document, m, 'topline')
526 remove_option(document, m, 'bottomline')
531 for k in range(nrows*ncols):
532 m = find_token(document.body, "<cell", m)
533 mc_info.append(get_option(document, m, 'multicolumn', '0'))
536 for l in range(nrows):
537 for k in range(ncols):
538 m = find_token(document.body, '<cell', m)
539 if mc_info[l*ncols + k] == '0':
540 r = set_option(document, m, 'topline', row_info[l][0])
541 r = set_option(document, m, 'bottomline', row_info[l][1])
542 r = set_option(document, m, 'leftline', col_info[k][0])
543 r = set_option(document, m, 'rightline', col_info[k][1])
544 elif mc_info[l*ncols + k] == '1':
546 while s < ncols and mc_info[l*ncols + s] == '2':
548 if s < ncols and mc_info[l*ncols + s] != '1':
549 r = set_option(document, m, 'rightline', col_info[k][1])
550 if k > 0 and mc_info[l*ncols + k - 1] == '0':
551 r = set_option(document, m, 'leftline', col_info[k][0])
556 def revert_tablines(document):
559 i = find_token(document.body, "\\begin_inset Tabular", i)
562 j = find_end_of_inset(document.body, i + 1)
564 document.warning("Malformed LyX document: Could not find end of tabular.")
568 nrows = int(document.body[i+1].split('"')[3])
569 ncols = int(document.body[i+1].split('"')[5])
572 for k in range(nrows*ncols):
573 m = find_token(document.body, "<cell", m)
574 top = get_option(document, m, 'topline', 'false')
575 bottom = get_option(document, m, 'bottomline', 'false')
576 left = get_option(document, m, 'leftline', 'false')
577 right = get_option(document, m, 'rightline', 'false')
578 lines.append([top, bottom, left, right])
581 # we will want to ignore longtable captions
584 for k in range(nrows):
585 m = find_token(document.body, "<row", m)
586 caption = get_option(document, m, 'caption', 'false')
587 caption_info.append([caption])
592 for k in range(ncols):
593 m = find_token(document.body, "<column", m)
595 for l in range(nrows):
596 left = lines[l*ncols + k][2]
597 if left == 'false' and caption_info[l] == 'false':
599 set_option(document, m, 'leftline', left)
601 for l in range(nrows):
602 right = lines[l*ncols + k][3]
603 if right == 'false' and caption_info[l] == 'false':
605 set_option(document, m, 'rightline', right)
609 for k in range(nrows):
610 m = find_token(document.body, "<row", m)
612 for l in range(ncols):
613 top = lines[k*ncols + l][0]
616 if caption_info[k] == 'false':
618 set_option(document, m, 'topline', top)
620 for l in range(ncols):
621 bottom = lines[k*ncols + l][1]
622 if bottom == 'false':
624 if caption_info[k] == 'false':
626 set_option(document, m, 'bottomline', bottom)
632 def fix_wrong_tables(document):
635 i = find_token(document.body, "\\begin_inset Tabular", i)
638 j = find_end_of_inset(document.body, i + 1)
640 document.warning("Malformed LyX document: Could not find end of tabular.")
644 nrows = int(document.body[i+1].split('"')[3])
645 ncols = int(document.body[i+1].split('"')[5])
647 for l in range(nrows):
649 for k in range(ncols):
650 m = find_token(document.body, '<cell', m)
652 if document.body[m].find('multicolumn') != -1:
653 multicol_cont = int(document.body[m].split('"')[1])
655 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
656 document.body[m] = document.body[m][:5] + document.body[m][21:]
659 prev_multicolumn = multicol_cont
666 def close_begin_deeper(document):
670 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
675 if document.body[i][:13] == "\\begin_deeper":
682 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
685 def long_charstyle_names(document):
688 i = find_token(document.body, "\\begin_inset CharStyle", i)
691 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
694 def revert_long_charstyle_names(document):
697 i = find_token(document.body, "\\begin_inset CharStyle", i)
700 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
704 def axe_show_label(document):
707 i = find_token(document.body, "\\begin_inset CharStyle", i)
710 if document.body[i + 1].find("show_label") != -1:
711 if document.body[i + 1].find("true") != -1:
712 document.body[i + 1] = "status open"
713 del document.body[ i + 2]
715 if document.body[i + 1].find("false") != -1:
716 document.body[i + 1] = "status collapsed"
717 del document.body[ i + 2]
719 document.warning("Malformed LyX document: show_label neither false nor true.")
721 document.warning("Malformed LyX document: show_label missing in CharStyle.")
726 def revert_show_label(document):
729 i = find_token(document.body, "\\begin_inset CharStyle", i)
732 if document.body[i + 1].find("status open") != -1:
733 document.body.insert(i + 1, "show_label true")
735 if document.body[i + 1].find("status collapsed") != -1:
736 document.body.insert(i + 1, "show_label false")
738 document.warning("Malformed LyX document: no legal status line in CharStyle.")
741 def revert_begin_modules(document):
744 i = find_token(document.header, "\\begin_modules", i)
747 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
749 # this should not happen
751 document.header[i : j + 1] = []
753 def convert_flex(document):
754 "Convert CharStyle to Flex"
757 i = find_token(document.body, "\\begin_inset CharStyle", i)
760 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
762 def revert_flex(document):
763 "Convert Flex to CharStyle"
766 i = find_token(document.body, "\\begin_inset Flex", i)
769 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
772 # Discard PDF options for hyperref
773 def revert_pdf_options(document):
774 "Revert PDF options for hyperref."
775 # store the PDF options and delete the entries from the Lyx file
783 bookmarksnumbered = ""
785 bookmarksopenlevel = ""
793 i = find_token(document.header, "\\use_hyperref", i)
795 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
796 del document.header[i]
797 i = find_token(document.header, "\\pdf_store_options", i)
799 del document.header[i]
800 i = find_token(document.header, "\\pdf_title", 0)
802 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
803 title = ' pdftitle={' + title + '}'
804 del document.header[i]
805 i = find_token(document.header, "\\pdf_author", 0)
807 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
809 author = ' pdfauthor={' + author + '}'
811 author = ',\n pdfauthor={' + author + '}'
812 del document.header[i]
813 i = find_token(document.header, "\\pdf_subject", 0)
815 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
816 if title == "" and author == "":
817 subject = ' pdfsubject={' + subject + '}'
819 subject = ',\n pdfsubject={' + subject + '}'
820 del document.header[i]
821 i = find_token(document.header, "\\pdf_keywords", 0)
823 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
824 if title == "" and author == "" and subject == "":
825 keywords = ' pdfkeywords={' + keywords + '}'
827 keywords = ',\n pdfkeywords={' + keywords + '}'
828 del document.header[i]
829 i = find_token(document.header, "\\pdf_bookmarks", 0)
831 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
832 bookmarks = ',\n bookmarks=' + bookmarks
833 del document.header[i]
834 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
836 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
837 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
838 del document.header[i]
839 i = find_token(document.header, "\\pdf_bookmarksopen", i)
841 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
842 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
843 del document.header[i]
844 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
846 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
847 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
848 del document.header[i]
849 i = find_token(document.header, "\\pdf_breaklinks", i)
851 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
852 breaklinks = ',\n breaklinks=' + breaklinks
853 del document.header[i]
854 i = find_token(document.header, "\\pdf_pdfborder", i)
856 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
857 if pdfborder == 'true':
858 pdfborder = ',\n pdfborder={0 0 0}'
860 pdfborder = ',\n pdfborder={0 0 1}'
861 del document.header[i]
862 i = find_token(document.header, "\\pdf_colorlinks", i)
864 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
865 colorlinks = ',\n colorlinks=' + colorlinks
866 del document.header[i]
867 i = find_token(document.header, "\\pdf_backref", i)
869 backref = get_value_string(document.header, '\\pdf_backref', 0)
870 backref = ',\n backref=' + backref
871 del document.header[i]
872 i = find_token(document.header, "\\pdf_pagebackref", i)
874 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
875 pagebackref = ',\n pagebackref=' + pagebackref
876 del document.header[i]
877 i = find_token(document.header, "\\pdf_pagemode", 0)
879 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
880 pagemode = ',\n pdfpagemode=' + pagemode
881 del document.header[i]
882 i = find_token(document.header, "\\pdf_quoted_options", 0)
884 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
885 if title == "" and author == "" and subject == "" and keywords == "":
886 otheroptions = ' ' + otheroptions
888 otheroptions = ',\n ' + otheroptions
889 del document.header[i]
891 # write to the preamble when hyperref was used
893 # preamble write preparations
894 # bookmark numbers are only output when they are turned on
895 if bookmarksopen == ',\n bookmarksopen=true':
896 bookmarksopen = bookmarksopen + bookmarksopenlevel
897 if bookmarks == ',\n bookmarks=true':
898 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
900 bookmarks = bookmarks
901 # hypersetup is only output when there are things to be set up
902 setupstart = '\\hypersetup{%\n'
904 if otheroptions == "" and title == "" and author == ""\
905 and subject == "" and keywords == "":
909 # babel must be loaded before hyperref and hyperref the first part
910 # of the preamble, like in LyX 1.6
911 insert_to_preamble(0, document,
912 '% Commands inserted by lyx2lyx for PDF properties\n'
913 + '\\usepackage{babel}\n'
914 + '\\usepackage[unicode=true'
933 def remove_inzip_options(document):
934 "Remove inzipName and embed options from the Graphics inset"
937 i = find_token(document.body, "\\begin_inset Graphics", i)
940 j = find_end_of_inset(document.body, i + 1)
943 document.warning("Malformed LyX document: Could not find end of graphics inset.")
944 # If there's a inzip param, just remove that
945 k = find_token(document.body, "\tinzipName", i + 1, j)
948 # embed option must follow the inzipName option
949 del document.body[k+1]
953 def convert_inset_command(document):
956 \begin_inset LatexCommand cmd
958 \begin_inset CommandInset InsetType
963 i = find_token(document.body, "\\begin_inset LatexCommand", i)
966 line = document.body[i]
967 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
971 #this is adapted from factory.cpp
972 if cmdName[0:4].lower() == "cite":
973 insetName = "citation"
974 elif cmdName == "url" or cmdName == "htmlurl":
976 elif cmdName[-3:] == "ref":
978 elif cmdName == "tableofcontents":
980 elif cmdName == "printnomenclature":
981 insetName = "nomencl_print"
982 elif cmdName == "printindex":
983 insetName = "index_print"
986 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
987 document.body[i : i+1] = insertion
990 def revert_inset_command(document):
993 \begin_inset CommandInset InsetType
996 \begin_inset LatexCommand cmd
997 Some insets may end up being converted to insets earlier versions of LyX
998 will not be able to recognize. Not sure what to do about that.
1002 i = find_token(document.body, "\\begin_inset CommandInset", i)
1005 nextline = document.body[i+1]
1006 r = re.compile(r'LatexCommand\s+(.*)$')
1007 m = r.match(nextline)
1009 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
1012 cmdName = m.group(1)
1013 insertion = ["\\begin_inset LatexCommand " + cmdName]
1014 document.body[i : i+2] = insertion
1017 def convert_wrapfig_options(document):
1018 "Convert optional options for wrap floats (wrapfig)."
1019 # adds the tokens "lines", "placement", and "overhang"
1022 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1025 document.body.insert(i + 1, "lines 0")
1026 j = find_token(document.body, "placement", i)
1027 # placement can be already set or not; if not, set it
1029 document.body.insert(i + 3, "overhang 0col%")
1031 document.body.insert(i + 2, "placement o")
1032 document.body.insert(i + 3, "overhang 0col%")
1036 def revert_wrapfig_options(document):
1037 "Revert optional options for wrap floats (wrapfig)."
1040 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1043 j = find_end_of_inset(document.body, i)
1045 document.warning("Can't find end of Wrap inset at line " + str(i))
1048 k = find_default_layout(document, i, j)
1050 document.warning("Can't find default layout for Wrap figure!")
1053 # Options should be between i and k now
1054 l = find_token(document.body, "lines", i, k)
1056 document.warning("Can't find lines option for Wrap figure!")
1059 m = find_token(document.body, "overhang", i + 1, k)
1061 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1064 # Do these in reverse order
1065 del document.body[m]
1066 del document.body[l]
1070 def convert_latexcommand_index(document):
1071 "Convert from LatexCommand form to collapsable form."
1073 r1 = re.compile('name "(.*)"')
1075 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1078 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1080 j = find_end_of_inset(document.body, i + 2)
1082 document.warning("Unable to find end of index inset at line " + i + "!")
1085 m = r1.match(document.body[i + 2])
1087 document.warning("Unable to match: " + document.body[i+2])
1088 # this can happen with empty index insets!
1091 fullcontent = m.group(1)
1092 linelist = latex2lyx(fullcontent)
1093 #document.warning(fullcontent)
1095 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1096 linelist + ["\\end_layout"]
1097 document.body[i : j] = linelist
1098 i += len(linelist) - (j - i)
1101 def revert_latexcommand_index(document):
1102 "Revert from collapsable form to LatexCommand form."
1105 i = find_token(document.body, "\\begin_inset Index", i)
1108 j = find_end_of_inset(document.body, i + 1)
1112 content = lyx2latex(document, document.body[i:j])
1114 content = content.replace('"', r'\"')
1115 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1116 "name " + '"' + content + '"', ""]
1120 def revert_wraptable(document):
1121 "Revert wrap table to wrap figure."
1124 i = find_token(document.body, "\\begin_inset Wrap table", i)
1127 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1131 def revert_vietnamese(document):
1132 "Set language Vietnamese to English"
1133 # Set document language from Vietnamese to English
1135 if document.language == "vietnamese":
1136 document.language = "english"
1137 i = find_token(document.header, "\\language", 0)
1139 document.header[i] = "\\language english"
1142 j = find_token(document.body, "\\lang vietnamese", j)
1145 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1149 def convert_japanese_cjk(document):
1150 "Set language japanese to japanese-cjk"
1151 # Set document language from japanese-plain to japanese
1153 if document.language == "japanese":
1154 document.language = "japanese-cjk"
1155 i = find_token(document.header, "\\language", 0)
1157 document.header[i] = "\\language japanese-cjk"
1160 j = find_token(document.body, "\\lang japanese", j)
1163 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1167 def revert_japanese(document):
1168 "Set language japanese-plain to japanese"
1169 # Set document language from japanese-plain to japanese
1171 if document.language == "japanese-plain":
1172 document.language = "japanese"
1173 i = find_token(document.header, "\\language", 0)
1175 document.header[i] = "\\language japanese"
1178 j = find_token(document.body, "\\lang japanese-plain", j)
1181 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1185 def revert_japanese_cjk(document):
1186 "Set language japanese-cjk to japanese"
1187 # Set document language from japanese-plain to japanese
1189 if document.language == "japanese-cjk":
1190 document.language = "japanese"
1191 i = find_token(document.header, "\\language", 0)
1193 document.header[i] = "\\language japanese"
1196 j = find_token(document.body, "\\lang japanese-cjk", j)
1199 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1203 def revert_japanese_encoding(document):
1204 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1205 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1207 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1209 document.header[i] = "\\inputencoding EUC-JP"
1211 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1213 document.header[j] = "\\inputencoding JIS"
1215 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1216 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1217 document.header[k] = "\\inputencoding UTF8"
1220 def revert_inset_info(document):
1221 'Replace info inset with its content'
1224 i = find_token(document.body, '\\begin_inset Info', i)
1227 j = find_end_of_inset(document.body, i + 1)
1230 document.warning("Malformed LyX document: Could not find end of Info inset.")
1233 for k in range(i, j+1):
1234 if document.body[k].startswith("arg"):
1235 arg = document.body[k][3:].strip()
1236 # remove embracing quotation marks
1239 if arg[len(arg) - 1] == '"':
1240 arg = arg[:len(arg) - 1]
1241 # \" to straight quote
1242 arg = arg.replace(r'\"','"')
1243 if document.body[k].startswith("type"):
1244 type = document.body[k][4:].strip().strip('"')
1245 # I think there is a newline after \\end_inset, which should be removed.
1246 if document.body[j + 1].strip() == "":
1247 document.body[i : (j + 2)] = [type + ':' + arg]
1249 document.body[i : (j + 1)] = [type + ':' + arg]
1252 def convert_pdf_options(document):
1253 # Set the pdfusetitle tag, delete the pdf_store_options,
1254 # set quotes for bookmarksopenlevel"
1255 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1257 k = find_token(document.header, "\\use_hyperref", 0)
1258 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1259 k = find_token(document.header, "\\pdf_store_options", 0)
1261 del document.header[k]
1262 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1264 document.header[i] = document.header[i].replace('"', '')
1267 def revert_pdf_options_2(document):
1268 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1269 k = find_token(document.header, "\\use_hyperref", 0)
1270 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1272 del document.header[i]
1273 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1275 values = document.header[i].split()
1276 values[1] = ' "' + values[1] + '"'
1277 document.header[i] = ''.join(values)
1280 def convert_htmlurl(document):
1281 'Convert "htmlurl" to "href" insets for docbook'
1282 if document.backend != "docbook":
1286 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1289 document.body[i] = "\\begin_inset CommandInset href"
1290 document.body[i + 1] = "LatexCommand href"
1294 def convert_url(document):
1295 'Convert url insets to url charstyles'
1296 if document.backend == "docbook":
1300 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1303 n = find_token(document.body, "name", i)
1305 # place the URL name in typewriter before the new URL insert
1306 # grab the name 'bla' from the e.g. the line 'name "bla"',
1307 # therefore start with the 6th character
1308 name = document.body[n][6:-1]
1309 newname = [name + " "]
1310 document.body[i:i] = newname
1312 j = find_token(document.body, "target", i)
1314 document.warning("Malformed LyX document: Can't find target for url inset")
1317 target = document.body[j][8:-1]
1318 k = find_token(document.body, "\\end_inset", j)
1320 document.warning("Malformed LyX document: Can't find end of url inset")
1323 newstuff = ["\\begin_inset Flex URL",
1324 "status collapsed", "",
1325 "\\begin_layout Standard",
1330 document.body[i:k] = newstuff
1333 def convert_ams_classes(document):
1334 tc = document.textclass
1335 if (tc != "amsart" and tc != "amsart-plain" and
1336 tc != "amsart-seq" and tc != "amsbook"):
1338 if tc == "amsart-plain":
1339 document.textclass = "amsart"
1340 document.set_textclass()
1341 document.add_module("Theorems (Starred)")
1343 if tc == "amsart-seq":
1344 document.textclass = "amsart"
1345 document.set_textclass()
1346 document.add_module("Theorems (AMS)")
1348 #Now we want to see if any of the environments in the extended theorems
1349 #module were used in this document. If so, we'll add that module, too.
1350 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1351 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1354 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1357 i = find_token(document.body, "\\begin_layout", i)
1360 m = r.match(document.body[i])
1362 # This is an empty layout
1363 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1367 if layouts.count(m) != 0:
1368 document.add_module("Theorems (AMS-Extended)")
1372 def revert_href(document):
1373 'Reverts hyperlink insets (href) to url insets (url)'
1376 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1379 document.body[i : i + 2] = \
1380 ["\\begin_inset CommandInset url", "LatexCommand url"]
1383 def revert_url(document):
1384 'Reverts Flex URL insets to old-style URL insets'
1387 i = find_token(document.body, "\\begin_inset Flex URL", i)
1390 j = find_end_of_inset(document.body, i)
1392 document.warning("Can't find end of inset in revert_url!")
1394 k = find_default_layout(document, i, j)
1396 document.warning("Can't find default layout in revert_url!")
1399 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1400 if l == -1 or l >= j:
1401 document.warning("Can't find end of default layout in revert_url!")
1404 # OK, so the inset's data is between lines k and l.
1405 data = " ".join(document.body[k+1:l])
1407 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1409 document.body[i:j+1] = newinset
1410 i = i + len(newinset)
1413 def convert_include(document):
1414 'Converts include insets to new format.'
1416 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1418 i = find_token(document.body, "\\begin_inset Include", i)
1421 line = document.body[i]
1422 previewline = document.body[i + 1]
1425 document.warning("Unable to match line " + str(i) + " of body!")
1431 insertion = ["\\begin_inset CommandInset include",
1432 "LatexCommand " + cmd, previewline,
1433 "filename \"" + fn + "\""]
1436 insertion.append("lstparams " + '"' + opt + '"')
1438 document.body[i : i + 2] = insertion
1442 def revert_include(document):
1443 'Reverts include insets to old format.'
1445 r0 = re.compile('preview.*')
1446 r1 = re.compile('LatexCommand (.+)')
1447 r2 = re.compile('filename "(.+)"')
1448 r3 = re.compile('lstparams "(.*)"')
1450 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1454 m = r1.match(document.body[nextline])
1456 document.warning("Malformed LyX document: No LatexCommand line for `" +
1457 document.body[i] + "' on line " + str(i) + ".")
1462 if r0.match(document.body[nextline]):
1463 previewline = document.body[nextline]
1467 m = r2.match(document.body[nextline])
1469 document.warning("Malformed LyX document: No filename line for `" + \
1470 document.body[i] + "' on line " + str(i) + ".")
1476 if (cmd == "lstinputlisting"):
1477 m = r3.match(document.body[nextline])
1479 options = m.group(1)
1482 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1484 newline += ("[" + options + "]")
1485 insertion = [newline]
1486 if previewline != "":
1487 insertion.append(previewline)
1488 document.body[i : nextline] = insertion
1492 def revert_albanian(document):
1493 "Set language Albanian to English"
1495 if document.language == "albanian":
1496 document.language = "english"
1497 i = find_token(document.header, "\\language", 0)
1499 document.header[i] = "\\language english"
1502 j = find_token(document.body, "\\lang albanian", j)
1505 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1509 def revert_lowersorbian(document):
1510 "Set language lower Sorbian to English"
1512 if document.language == "lowersorbian":
1513 document.language = "english"
1514 i = find_token(document.header, "\\language", 0)
1516 document.header[i] = "\\language english"
1519 j = find_token(document.body, "\\lang lowersorbian", j)
1522 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1526 def revert_uppersorbian(document):
1527 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1529 if document.language == "uppersorbian":
1530 document.language = "usorbian"
1531 i = find_token(document.header, "\\language", 0)
1533 document.header[i] = "\\language usorbian"
1536 j = find_token(document.body, "\\lang uppersorbian", j)
1539 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1543 def convert_usorbian(document):
1544 "Set language usorbian to uppersorbian"
1546 if document.language == "usorbian":
1547 document.language = "uppersorbian"
1548 i = find_token(document.header, "\\language", 0)
1550 document.header[i] = "\\language uppersorbian"
1553 j = find_token(document.body, "\\lang usorbian", j)
1556 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1560 def convert_macro_global(document):
1561 "Remove TeX code command \global when it is in front of a macro"
1562 # math macros are nowadays already defined \global, so that an additional
1563 # \global would make the document uncompilable, see
1564 # http://bugzilla.lyx.org/show_bug.cgi?id=5371
1565 # We're looking for something like this:
1569 # \begin_layout Plain Layout
1579 # \begin_inset FormulaMacro
1580 # \renewcommand{\foo}{123}
1584 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1587 # if i <= 13, then there isn't enough room for the ERT
1591 if document.body[i-6] == "global":
1592 del document.body[i-13 : i]
1598 def revert_macro_optional_params(document):
1599 "Convert macro definitions with optional parameters into ERTs"
1600 # Stub to convert macro definitions with one or more optional parameters
1601 # into uninterpreted ERT insets
1604 def revert_hyperlinktype(document):
1605 'Reverts hyperlink type'
1609 i = find_token(document.body, "target", i)
1612 j = find_token(document.body, "type", i)
1616 del document.body[j]
1620 def revert_pagebreak(document):
1621 'Reverts pagebreak to ERT'
1624 i = find_token(document.body, "\\pagebreak", i)
1627 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1628 '\\begin_layout Standard\n\n\n\\backslash\n' \
1629 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1633 def revert_linebreak(document):
1634 'Reverts linebreak to ERT'
1637 i = find_token(document.body, "\\linebreak", i)
1640 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1641 '\\begin_layout Standard\n\n\n\\backslash\n' \
1642 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1646 def revert_latin(document):
1647 "Set language Latin to English"
1649 if document.language == "latin":
1650 document.language = "english"
1651 i = find_token(document.header, "\\language", 0)
1653 document.header[i] = "\\language english"
1656 j = find_token(document.body, "\\lang latin", j)
1659 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1663 def revert_samin(document):
1664 "Set language North Sami to English"
1666 if document.language == "samin":
1667 document.language = "english"
1668 i = find_token(document.header, "\\language", 0)
1670 document.header[i] = "\\language english"
1673 j = find_token(document.body, "\\lang samin", j)
1676 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1680 def convert_serbocroatian(document):
1681 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1683 if document.language == "serbocroatian":
1684 document.language = "croatian"
1685 i = find_token(document.header, "\\language", 0)
1687 document.header[i] = "\\language croatian"
1690 j = find_token(document.body, "\\lang serbocroatian", j)
1693 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1697 def convert_framed_notes(document):
1698 "Convert framed notes to boxes. "
1701 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1704 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1713 'height_special "totalheight"']
1714 document.body[i:i+1] = subst
1718 def convert_module_names(document):
1719 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1720 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1721 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1722 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1723 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1724 modlist = document.get_module_list()
1725 if len(modlist) == 0:
1729 if modulemap.has_key(mod):
1730 newmodlist.append(modulemap[mod])
1732 document.warning("Can't find module %s in the module map!" % mod)
1733 newmodlist.append(mod)
1734 document.set_module_list(newmodlist)
1737 def revert_module_names(document):
1738 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1739 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1740 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1741 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1742 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1743 modlist = document.get_module_list()
1744 if len(modlist) == 0:
1748 if modulemap.has_key(mod):
1749 newmodlist.append(modulemap[mod])
1751 document.warning("Can't find module %s in the module map!" % mod)
1752 newmodlist.append(mod)
1753 document.set_module_list(newmodlist)
1756 def revert_colsep(document):
1757 i = find_token(document.header, "\\columnsep", 0)
1760 colsepline = document.header[i]
1761 r = re.compile(r'\\columnsep (.*)')
1762 m = r.match(colsepline)
1764 document.warning("Malformed column separation line!")
1767 del document.header[i]
1768 #it seems to be safe to add the package even if it is already used
1769 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1771 add_to_preamble(document, pretext)
1774 def revert_framed_notes(document):
1775 "Revert framed boxes to notes. "
1778 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1782 j = find_end_of_inset(document.body, i + 1)
1785 document.warning("Malformed LyX document: Could not find end of Box inset.")
1786 k = find_token(document.body, "status", i + 1, j)
1788 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1790 status = document.body[k]
1791 l = find_default_layout(document, i + 1, j)
1793 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1795 m = find_token(document.body, "\\end_layout", i + 1, j)
1797 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1799 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1800 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1801 if ibox == -1 and pbox == -1:
1802 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1803 del document.body[i+1:k]
1805 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1806 subst1 = [document.body[l],
1807 "\\begin_inset Note Shaded",
1809 '\\begin_layout Standard']
1810 document.body[l:l + 1] = subst1
1811 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1812 document.body[m:m + 1] = subst2
1816 def revert_slash(document):
1817 'Revert \\SpecialChar \\slash{} to ERT'
1819 while i < len(document.body):
1820 m = re.match(r'(.*)\\SpecialChar \\slash{}(.*)', document.body[i])
1825 '\\begin_inset ERT',
1826 'status collapsed', '',
1827 '\\begin_layout Standard',
1828 '', '', '\\backslash',
1833 document.body[i: i+1] = subst
1839 def revert_nobreakdash(document):
1840 'Revert \\SpecialChar \\nobreakdash- to ERT'
1842 while i < len(document.body):
1843 m = re.match(r'(.*)\\SpecialChar \\nobreakdash-(.*)', document.body[i])
1848 '\\begin_inset ERT',
1849 'status collapsed', '',
1850 '\\begin_layout Standard', '', '',
1856 document.body[i: i+1] = subst
1858 j = find_token(document.header, "\\use_amsmath", 0)
1860 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1862 document.header[j] = "\\use_amsmath 2"
1867 #Returns number of lines added/removed
1868 def revert_nocite_key(body, start, end):
1869 'key "..." -> \nocite{...}'
1870 r = re.compile(r'^key "(.*)"')
1874 m = r.match(body[i])
1876 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1877 j += 1 # because we added a line
1878 i += 2 # skip that line
1881 j -= 1 # because we deleted a line
1882 # no need to change i, since it now points to the next line
1886 def revert_nocite(document):
1887 "Revert LatexCommand nocite to ERT"
1890 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1893 if (document.body[i+1] != "LatexCommand nocite"):
1894 # note that we already incremented i
1897 insetEnd = find_end_of_inset(document.body, i)
1899 #this should not happen
1900 document.warning("End of CommandInset citation not found in revert_nocite!")
1903 paramLocation = i + 2 #start of the inset's parameters
1905 document.body[i:i+2] = \
1906 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1907 # that added two lines
1910 #print insetEnd, document.body[i: insetEnd + 1]
1911 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1912 #print insetEnd, document.body[i: insetEnd + 1]
1913 document.body.insert(insetEnd, "\\end_layout")
1914 document.body.insert(insetEnd + 1, "")
1918 def revert_btprintall(document):
1919 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1920 i = find_token(document.header, '\\use_bibtopic', 0)
1922 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1924 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1926 while i < len(document.body):
1927 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1930 j = find_end_of_inset(document.body, i + 1)
1932 #this should not happen
1933 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1934 j = len(document.body)
1935 # this range isn't really right, but it should be OK, since we shouldn't
1936 # see more than one matching line in each inset
1938 for k in range(i, j):
1939 if (document.body[k] == 'btprint "btPrintAll"'):
1940 del document.body[k]
1941 subst = ["\\begin_inset ERT",
1942 "status collapsed", "",
1943 "\\begin_layout Standard", "",
1948 document.body[i:i] = subst
1949 addlines = addedlines + len(subst) - 1
1953 def revert_bahasam(document):
1954 "Set language Bahasa Malaysia to Bahasa Indonesia"
1956 if document.language == "bahasam":
1957 document.language = "bahasa"
1958 i = find_token(document.header, "\\language", 0)
1960 document.header[i] = "\\language bahasa"
1963 j = find_token(document.body, "\\lang bahasam", j)
1966 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1970 def revert_interlingua(document):
1971 "Set language Interlingua to English"
1973 if document.language == "interlingua":
1974 document.language = "english"
1975 i = find_token(document.header, "\\language", 0)
1977 document.header[i] = "\\language english"
1980 j = find_token(document.body, "\\lang interlingua", j)
1983 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1987 def revert_serbianlatin(document):
1988 "Set language Serbian-Latin to Croatian"
1990 if document.language == "serbian-latin":
1991 document.language = "croatian"
1992 i = find_token(document.header, "\\language", 0)
1994 document.header[i] = "\\language croatian"
1997 j = find_token(document.body, "\\lang serbian-latin", j)
2000 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
2004 def revert_rotfloat(document):
2005 " Revert sideways custom floats. "
2008 # whitespace intended (exclude \\begin_inset FloatList)
2009 i = find_token(document.body, "\\begin_inset Float ", i)
2012 line = document.body[i]
2013 r = re.compile(r'\\begin_inset Float (.*)$')
2016 document.warning("Unable to match line " + str(i) + " of body!")
2019 floattype = m.group(1)
2020 if floattype == "figure" or floattype == "table":
2023 j = find_end_of_inset(document.body, i)
2025 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
2029 if get_value(document.body, 'sideways', i, j) == "false":
2032 l = find_default_layout(document, i + 1, j)
2034 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2036 subst = ['\\begin_layout Standard',
2037 '\\begin_inset ERT',
2038 'status collapsed', '',
2039 '\\begin_layout Standard', '', '',
2041 'end{sideways' + floattype + '}',
2042 '\\end_layout', '', '\\end_inset']
2043 document.body[j : j+1] = subst
2044 addedLines = len(subst) - 1
2045 del document.body[i+1 : l]
2046 addedLines -= (l-1) - (i+1)
2047 subst = ['\\begin_inset ERT', 'status collapsed', '',
2048 '\\begin_layout Standard', '', '', '\\backslash',
2049 'begin{sideways' + floattype + '}',
2050 '\\end_layout', '', '\\end_inset', '',
2052 document.body[i : i+1] = subst
2053 addedLines += len(subst) - 1
2054 if floattype == "algorithm":
2055 add_to_preamble(document,
2056 ['% Commands inserted by lyx2lyx for sideways algorithm float',
2057 '\\usepackage{rotfloat}',
2058 '\\floatstyle{ruled}',
2059 '\\newfloat{algorithm}{tbp}{loa}',
2060 '\\floatname{algorithm}{Algorithm}'])
2062 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
2066 def revert_widesideways(document):
2067 " Revert wide sideways floats. "
2070 # whitespace intended (exclude \\begin_inset FloatList)
2071 i = find_token(document.body, '\\begin_inset Float ', i)
2074 line = document.body[i]
2075 r = re.compile(r'\\begin_inset Float (.*)$')
2078 document.warning("Unable to match line " + str(i) + " of body!")
2081 floattype = m.group(1)
2082 if floattype != "figure" and floattype != "table":
2085 j = find_end_of_inset(document.body, i)
2087 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2090 if get_value(document.body, 'sideways', i, j) == "false" or \
2091 get_value(document.body, 'wide', i, j) == "false":
2094 l = find_default_layout(document, i + 1, j)
2096 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2098 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2099 'status collapsed', '',
2100 '\\begin_layout Standard', '', '', '\\backslash',
2101 'end{sideways' + floattype + '*}',
2102 '\\end_layout', '', '\\end_inset']
2103 document.body[j : j+1] = subst
2104 addedLines = len(subst) - 1
2105 del document.body[i+1:l-1]
2106 addedLines -= (l-1) - (i+1)
2107 subst = ['\\begin_inset ERT', 'status collapsed', '',
2108 '\\begin_layout Standard', '', '', '\\backslash',
2109 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2110 '\\end_inset', '', '\\end_layout', '']
2111 document.body[i : i+1] = subst
2112 addedLines += len(subst) - 1
2113 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2117 def revert_inset_embedding(document, type):
2118 ' Remove embed tag from certain type of insets'
2121 i = find_token(document.body, "\\begin_inset %s" % type, i)
2124 j = find_end_of_inset(document.body, i)
2126 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2129 k = find_token(document.body, "\tembed", i, j)
2131 k = find_token(document.body, "embed", i, j)
2133 del document.body[k]
2137 def revert_external_embedding(document):
2138 ' Remove embed tag from external inset '
2139 revert_inset_embedding(document, 'External')
2142 def convert_subfig(document):
2143 " Convert subfigures to subfloats. "
2147 i = find_token(document.body, '\\begin_inset Graphics', i)
2150 endInset = find_end_of_inset(document.body, i)
2152 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2155 k = find_token(document.body, '\tsubcaption', i, endInset)
2159 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2163 caption = document.body[l][16:].strip('"')
2164 del document.body[l]
2166 del document.body[k]
2168 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2169 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2170 '', '\\begin_layout Plain Layout'] + latex2lyx(caption) + \
2171 [ '\\end_layout', '', '\\end_inset', '',
2172 '\\end_layout', '', '\\begin_layout Plain Layout']
2173 document.body[i : i] = subst
2174 addedLines += len(subst)
2175 endInset += addedLines
2176 subst = ['', '\\end_inset', '', '\\end_layout']
2177 document.body[endInset : endInset] = subst
2178 addedLines += len(subst)
2182 def revert_subfig(document):
2183 " Revert subfloats. "
2186 # whitespace intended (exclude \\begin_inset FloatList)
2187 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2193 j = find_end_of_inset(document.body, i)
2195 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2196 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2198 continue # this will get us back to the outer loop, since j == -1
2199 # look for embedded float (= subfloat)
2200 # whitespace intended (exclude \\begin_inset FloatList)
2201 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2204 # is the subfloat aligned?
2205 al = find_token(document.body, '\\align ', k - 1, j)
2209 if get_value(document.body, '\\align', al) == "center":
2210 alignment_beg = "\\backslash\nbegin{centering}"
2211 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2212 elif get_value(document.body, '\\align', al) == "left":
2213 alignment_beg = "\\backslash\nbegin{raggedright}"
2214 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2215 elif get_value(document.body, '\\align', al) == "right":
2216 alignment_beg = "\\backslash\nbegin{raggedleft}"
2217 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2218 l = find_end_of_inset(document.body, k)
2220 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2223 continue # escape to the outer loop
2224 m = find_default_layout(document, k + 1, l)
2226 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2231 capend = find_end_of_inset(document.body, cap)
2233 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2237 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2239 lblend = find_end_of_inset(document.body, lbl + 1)
2241 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2243 for line in document.body[lbl:lblend + 1]:
2244 if line.startswith('name '):
2245 label = line.split()[1].strip('"')
2252 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2254 optend = find_end_of_inset(document.body, opt)
2256 document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
2258 optc = find_default_layout(document, opt, optend)
2260 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2262 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2263 for line in document.body[optc:optcend]:
2264 if not line.startswith('\\'):
2265 shortcap += line.strip()
2269 for line in document.body[cap:capend]:
2270 if line in document.body[lbl:lblend]:
2272 elif line in document.body[opt:optend]:
2274 elif not line.startswith('\\'):
2275 caption += line.strip()
2277 caption += "\\backslash\nlabel{" + label + "}"
2278 subst = '\\begin_layout Plain Layout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2279 '\\begin_layout Plain Layout\n\n}' + alignment_end + \
2280 '\n\\end_layout\n\n\\end_inset\n\n' \
2281 '\\end_layout\n\n\\begin_layout Plain Layout\n'
2282 subst = subst.split('\n')
2283 document.body[l : l+1] = subst
2284 addedLines = len(subst) - 1
2285 # this is before l and so is unchanged by the multiline insertion
2287 del document.body[cap:capend+1]
2288 addedLines -= (capend + 1 - cap)
2289 del document.body[k+1:m-1]
2290 addedLines -= (m - 1 - (k + 1))
2291 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2292 '\\begin_layout Plain Layout\n\n' + alignment_beg + '\\backslash\n' \
2294 if len(shortcap) > 0:
2295 insertion = insertion + "[" + shortcap + "]"
2296 if len(caption) > 0:
2297 insertion = insertion + "[" + caption + "]"
2298 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2299 insertion = insertion.split('\n')
2300 document.body[k : k + 1] = insertion
2301 addedLines += len(insertion) - 1
2303 del document.body[al]
2305 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2309 def revert_wrapplacement(document):
2310 " Revert placement options wrap floats (wrapfig). "
2313 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2316 e = find_end_of_inset(document.body, i)
2317 j = find_token(document.body, "placement", i + 1, e)
2319 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2322 r = re.compile("placement (o|i|l|r|O|I|L|R)")
2323 m = r.match(document.body[j])
2325 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2327 document.body[j] = "placement " + m.group(1).lower()
2331 def remove_extra_embedded_files(document):
2332 " Remove \extra_embedded_files from buffer params "
2333 i = find_token(document.header, '\\extra_embedded_files', 0)
2336 document.header.pop(i)
2339 def convert_spaceinset(document):
2340 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2342 while i < len(document.body):
2343 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2347 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2348 document.body[i: i+1] = subst
2354 def revert_spaceinset(document):
2355 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2358 i = find_token(document.body, "\\begin_inset Space", i)
2361 j = find_end_of_inset(document.body, i)
2363 document.warning("Malformed LyX document: Could not find end of space inset.")
2365 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2366 del document.body[j]
2369 def convert_hfill(document):
2370 " Convert hfill to space inset "
2373 i = find_token(document.body, "\\hfill", i)
2376 subst = document.body[i].replace('\\hfill', \
2377 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2378 subst = subst.split('\n')
2379 document.body[i : i+1] = subst
2383 def revert_hfills(document):
2384 ' Revert \\hfill commands '
2385 hfill = re.compile(r'\\hfill')
2386 dotfill = re.compile(r'\\dotfill')
2387 hrulefill = re.compile(r'\\hrulefill')
2390 i = find_token(document.body, "\\InsetSpace", i)
2393 if hfill.search(document.body[i]):
2394 document.body[i] = \
2395 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2398 if dotfill.search(document.body[i]):
2399 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2400 '\\begin_inset ERT\nstatus collapsed\n\n' \
2401 '\\begin_layout Standard\n\n\n\\backslash\n' \
2402 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2403 subst = subst.split('\n')
2404 document.body[i : i+1] = subst
2407 if hrulefill.search(document.body[i]):
2408 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2409 '\\begin_inset ERT\nstatus collapsed\n\n' \
2410 '\\begin_layout Standard\n\n\n\\backslash\n' \
2411 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2412 subst = subst.split('\n')
2413 document.body[i : i+1] = subst
2418 def revert_hspace(document):
2419 ' Revert \\InsetSpace \\hspace{} to ERT '
2421 hspace = re.compile(r'\\hspace{}')
2422 hstar = re.compile(r'\\hspace\*{}')
2424 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2427 length = get_value(document.body, '\\length', i+1)
2429 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2431 del document.body[i+1]
2433 if hstar.search(document.body[i]):
2434 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2435 '\\begin_inset ERT\nstatus collapsed\n\n' \
2436 '\\begin_layout Standard\n\n\n\\backslash\n' \
2437 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2438 subst = subst.split('\n')
2439 document.body[i : i+1] = subst
2440 addedLines += len(subst) - 1
2443 if hspace.search(document.body[i]):
2444 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2445 '\\begin_inset ERT\nstatus collapsed\n\n' \
2446 '\\begin_layout Standard\n\n\n\\backslash\n' \
2447 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2448 subst = subst.split('\n')
2449 document.body[i : i+1] = subst
2450 addedLines += len(subst) - 1
2456 def revert_protected_hfill(document):
2457 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2460 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2463 j = find_end_of_inset(document.body, i)
2465 document.warning("Malformed LyX document: Could not find end of space inset.")
2467 del document.body[j]
2468 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2469 '\\begin_inset ERT\nstatus collapsed\n\n' \
2470 '\\begin_layout Standard\n\n\n\\backslash\n' \
2471 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2472 subst = subst.split('\n')
2473 document.body[i : i+1] = subst
2477 def revert_leftarrowfill(document):
2478 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2481 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2484 j = find_end_of_inset(document.body, i)
2486 document.warning("Malformed LyX document: Could not find end of space inset.")
2488 del document.body[j]
2489 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2490 '\\begin_inset ERT\nstatus collapsed\n\n' \
2491 '\\begin_layout Standard\n\n\n\\backslash\n' \
2492 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2493 subst = subst.split('\n')
2494 document.body[i : i+1] = subst
2498 def revert_rightarrowfill(document):
2499 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2502 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2505 j = find_end_of_inset(document.body, i)
2507 document.warning("Malformed LyX document: Could not find end of space inset.")
2509 del document.body[j]
2510 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2511 '\\begin_inset ERT\nstatus collapsed\n\n' \
2512 '\\begin_layout Standard\n\n\n\\backslash\n' \
2513 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2514 subst = subst.split('\n')
2515 document.body[i : i+1] = subst
2519 def revert_upbracefill(document):
2520 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2523 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2526 j = find_end_of_inset(document.body, i)
2528 document.warning("Malformed LyX document: Could not find end of space inset.")
2530 del document.body[j]
2531 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2532 '\\begin_inset ERT\nstatus collapsed\n\n' \
2533 '\\begin_layout Standard\n\n\n\\backslash\n' \
2534 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2535 subst = subst.split('\n')
2536 document.body[i : i+1] = subst
2540 def revert_downbracefill(document):
2541 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2544 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2547 j = find_end_of_inset(document.body, i)
2549 document.warning("Malformed LyX document: Could not find end of space inset.")
2551 del document.body[j]
2552 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2553 '\\begin_inset ERT\nstatus collapsed\n\n' \
2554 '\\begin_layout Standard\n\n\n\\backslash\n' \
2555 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2556 subst = subst.split('\n')
2557 document.body[i : i+1] = subst
2561 def revert_local_layout(document):
2562 ' Revert local layout headers.'
2565 i = find_token(document.header, "\\begin_local_layout", i)
2568 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2570 # this should not happen
2572 document.header[i : j + 1] = []
2575 def convert_pagebreaks(document):
2576 ' Convert inline Newpage insets to new format '
2579 i = find_token(document.body, '\\newpage', i)
2582 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2586 i = find_token(document.body, '\\pagebreak', i)
2589 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2593 i = find_token(document.body, '\\clearpage', i)
2596 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2600 i = find_token(document.body, '\\cleardoublepage', i)
2603 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2607 def revert_pagebreaks(document):
2608 ' Revert \\begin_inset Newpage to previous inline format '
2611 i = find_token(document.body, '\\begin_inset Newpage', i)
2614 j = find_end_of_inset(document.body, i)
2616 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2618 del document.body[j]
2619 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2620 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2621 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2622 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2625 def convert_linebreaks(document):
2626 ' Convert inline Newline insets to new format '
2629 i = find_token(document.body, '\\newline', i)
2632 document.body[i:i+1] = ['\\begin_inset Newline newline',
2636 i = find_token(document.body, '\\linebreak', i)
2639 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2643 def revert_linebreaks(document):
2644 ' Revert \\begin_inset Newline to previous inline format '
2647 i = find_token(document.body, '\\begin_inset Newline', i)
2650 j = find_end_of_inset(document.body, i)
2652 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2654 del document.body[j]
2655 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2656 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2659 def convert_japanese_plain(document):
2660 ' Set language japanese-plain to japanese '
2662 if document.language == "japanese-plain":
2663 document.language = "japanese"
2664 i = find_token(document.header, "\\language", 0)
2666 document.header[i] = "\\language japanese"
2669 j = find_token(document.body, "\\lang japanese-plain", j)
2672 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2676 def revert_pdfpages(document):
2677 ' Revert pdfpages external inset to ERT '
2680 i = find_token(document.body, "\\begin_inset External", i)
2683 j = find_end_of_inset(document.body, i)
2685 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2688 if get_value(document.body, 'template', i, j) == "PDFPages":
2689 filename = get_value(document.body, 'filename', i, j)
2691 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2692 for k in range(i, j):
2693 m = r.match(document.body[k])
2696 angle = get_value(document.body, 'rotateAngle', i, j)
2697 width = get_value(document.body, 'width', i, j)
2698 height = get_value(document.body, 'height', i, j)
2699 scale = get_value(document.body, 'scale', i, j)
2700 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2704 options += ",angle=" + angle
2706 options += "angle=" + angle
2709 options += ",width=" + convert_len(width)
2711 options += "width=" + convert_len(width)
2714 options += ",height=" + convert_len(height)
2716 options += "height=" + convert_len(height)
2719 options += ",scale=" + scale
2721 options += "scale=" + scale
2722 if keepAspectRatio != '':
2724 options += ",keepaspectratio"
2726 options += "keepaspectratio"
2728 options = '[' + options + ']'
2729 del document.body[i+1:j+1]
2730 document.body[i:i+1] = ['\\begin_inset ERT',
2733 '\\begin_layout Standard',
2736 'includepdf' + options + '{' + filename + '}',
2740 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2746 def revert_mexican(document):
2747 ' Set language Spanish(Mexico) to Spanish '
2749 if document.language == "spanish-mexico":
2750 document.language = "spanish"
2751 i = find_token(document.header, "\\language", 0)
2753 document.header[i] = "\\language spanish"
2756 j = find_token(document.body, "\\lang spanish-mexico", j)
2759 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2763 def remove_embedding(document):
2764 ' Remove embed tag from all insets '
2765 revert_inset_embedding(document, 'Graphics')
2766 revert_inset_embedding(document, 'External')
2767 revert_inset_embedding(document, 'CommandInset include')
2768 revert_inset_embedding(document, 'CommandInset bibtex')
2771 def revert_master(document):
2772 ' Remove master param '
2773 i = find_token(document.header, "\\master", 0)
2775 del document.header[i]
2778 def revert_graphics_group(document):
2779 ' Revert group information from graphics insets '
2782 i = find_token(document.body, "\\begin_inset Graphics", i)
2785 j = find_end_of_inset(document.body, i)
2787 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2790 k = find_token(document.body, " groupId", i, j)
2794 del document.body[k]
2798 def update_apa_styles(document):
2799 ' Replace obsolete styles '
2801 if document.textclass != "apa":
2804 obsoletedby = { "Acknowledgments": "Acknowledgements",
2805 "Section*": "Section",
2806 "Subsection*": "Subsection",
2807 "Subsubsection*": "Subsubsection",
2808 "Paragraph*": "Paragraph",
2809 "Subparagraph*": "Subparagraph"}
2812 i = find_token(document.body, "\\begin_layout", i)
2816 layout = document.body[i][14:]
2817 if layout in obsoletedby:
2818 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2823 def convert_paper_sizes(document):
2824 ' exchange size options legalpaper and executivepaper to correct order '
2825 # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2828 i = find_token(document.header, "\\papersize executivepaper", 0)
2830 document.header[i] = "\\papersize legalpaper"
2832 j = find_token(document.header, "\\papersize legalpaper", 0)
2834 document.header[j] = "\\papersize executivepaper"
2837 def revert_paper_sizes(document):
2838 ' exchange size options legalpaper and executivepaper to correct order '
2841 i = find_token(document.header, "\\papersize executivepaper", 0)
2843 document.header[i] = "\\papersize legalpaper"
2845 j = find_token(document.header, "\\papersize legalpaper", 0)
2847 document.header[j] = "\\papersize executivepaper"
2850 def convert_InsetSpace(document):
2851 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2854 i = find_token(document.body, "\\begin_inset Space", i)
2857 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2860 def revert_InsetSpace(document):
2861 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2864 i = find_token(document.body, "\\begin_inset space", i)
2867 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2870 def convert_display_enum(document):
2871 " Convert 'display foo' to 'display false/true'"
2874 i = find_token(document.body, "\tdisplay", i)
2877 val = get_value(document.body, 'display', i)
2879 document.body[i] = document.body[i].replace('none', 'false')
2880 if val == "default":
2881 document.body[i] = document.body[i].replace('default', 'true')
2882 if val == "monochrome":
2883 document.body[i] = document.body[i].replace('monochrome', 'true')
2884 if val == "grayscale":
2885 document.body[i] = document.body[i].replace('grayscale', 'true')
2887 document.body[i] = document.body[i].replace('color', 'true')
2888 if val == "preview":
2889 document.body[i] = document.body[i].replace('preview', 'true')
2893 def revert_display_enum(document):
2894 " Revert 'display false/true' to 'display none/color'"
2897 i = find_token(document.body, "\tdisplay", i)
2900 val = get_value(document.body, 'display', i)
2902 document.body[i] = document.body[i].replace('false', 'none')
2904 document.body[i] = document.body[i].replace('true', 'default')
2908 def remove_fontsCJK(document):
2909 ' Remove font_cjk param '
2910 i = find_token(document.header, "\\font_cjk", 0)
2912 del document.header[i]
2915 def convert_plain_layout(document):
2916 " Convert 'PlainLayout' to 'Plain Layout'"
2919 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2922 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2923 '\\begin_layout Plain Layout')
2927 def revert_plain_layout(document):
2928 " Convert 'PlainLayout' to 'Plain Layout'"
2931 i = find_token(document.body, '\\begin_layout Plain Layout', i)
2934 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2935 '\\begin_layout PlainLayout')
2939 def revert_plainlayout(document):
2940 " Convert 'PlainLayout' to 'Plain Layout'"
2943 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2946 # This will be incorrect for some document classes, since Standard is not always
2947 # the default. But (a) it is probably the best we can do and (b) it will actually
2948 # work, in fact, since an unknown layout will be converted to default.
2949 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2950 '\\begin_layout Standard')
2954 def revert_polytonicgreek(document):
2955 "Set language polytonic Greek to Greek"
2957 if document.language == "polutonikogreek":
2958 document.language = "greek"
2959 i = find_token(document.header, "\\language", 0)
2961 document.header[i] = "\\language greek"
2964 j = find_token(document.body, "\\lang polutonikogreek", j)
2967 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2971 def revert_removed_modules(document):
2974 i = find_token(document.header, "\\begin_remove_modules", i)
2977 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
2979 # this should not happen
2981 document.header[i : j + 1] = []
2984 def add_plain_layout(document):
2987 i = find_token(document.body, "\\begin_layout", i)
2990 if len(document.body[i].split()) == 1:
2991 document.body[i] = "\\begin_layout Plain Layout"
2995 def revert_tabulators(document):
2996 "Revert tabulators to 4 spaces"
2999 i = find_token(document.body, "\t", i)
3002 document.body[i] = document.body[i].replace("\t", " ")
3006 def revert_tabsize(document):
3007 "Revert the tabsize parameter of listings"
3011 # either it is the only parameter
3012 i = find_token(document.body, 'lstparams "tabsize=4"', i)
3014 del document.body[i]
3016 j = find_token(document.body, "lstparams", j)
3019 pos = document.body[j].find(",tabsize=")
3020 document.body[j] = document.body[j][:pos] + '"'
3025 def revert_mongolian(document):
3026 "Set language Mongolian to English"
3028 if document.language == "mongolian":
3029 document.language = "english"
3030 i = find_token(document.header, "\\language", 0)
3032 document.header[i] = "\\language english"
3035 j = find_token(document.body, "\\lang mongolian", j)
3038 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
3042 def revert_default_options(document):
3043 ' Remove param use_default_options '
3044 i = find_token(document.header, "\\use_default_options", 0)
3046 del document.header[i]
3049 def convert_default_options(document):
3050 ' Add param use_default_options and set it to false '
3051 i = find_token(document.header, "\\textclass", 0)
3053 document.warning("Malformed LyX document: Missing `\\textclass'.")
3055 document.header.insert(i, '\\use_default_options false')
3058 def revert_backref_options(document):
3059 ' Revert option pdf_backref=page to pagebackref '
3060 i = find_token(document.header, "\\pdf_backref page", 0)
3062 document.header[i] = "\\pdf_pagebackref true"
3065 def convert_backref_options(document):
3066 ' We have changed the option pagebackref to backref=true '
3067 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3069 document.header[i] = "\\pdf_backref page"
3070 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3072 del document.header[j]
3073 # backref=true was not a valid option, we meant backref=section
3074 k = find_token(document.header, "\\pdf_backref true", 0)
3075 if k != -1 and i != -1:
3076 del document.header[k]
3077 elif k != -1 and j != -1:
3078 document.header[k] = "\\pdf_backref section"
3081 def convert_charstyle_element(document):
3082 "Convert CharStyle to Element for docbook backend"
3083 if document.backend != "docbook":
3087 i = find_token(document.body, "\\begin_inset Flex CharStyle:", i)
3090 document.body[i] = document.body[i].replace('\\begin_inset Flex CharStyle:',
3091 '\\begin_inset Flex Element:')
3093 def revert_charstyle_element(document):
3094 "Convert Element to CharStyle for docbook backend"
3095 if document.backend != "docbook":
3099 i = find_token(document.body, "\\begin_inset Flex Element:", i)
3102 document.body[i] = document.body[i].replace('\\begin_inset Flex Element:',
3103 '\\begin_inset Flex CharStyle:')
3109 supported_versions = ["1.6.0","1.6"]
3110 convert = [[277, [fix_wrong_tables]],
3111 [278, [close_begin_deeper]],
3112 [279, [long_charstyle_names]],
3113 [280, [axe_show_label]],
3116 [283, [convert_flex]],
3120 [287, [convert_wrapfig_options]],
3121 [288, [convert_inset_command]],
3122 [289, [convert_latexcommand_index]],
3125 [292, [convert_japanese_cjk]],
3127 [294, [convert_pdf_options]],
3128 [295, [convert_htmlurl, convert_url]],
3129 [296, [convert_include]],
3130 [297, [convert_usorbian]],
3131 [298, [convert_macro_global]],
3136 [303, [convert_serbocroatian]],
3137 [304, [convert_framed_notes]],
3144 [311, [convert_ams_classes]],
3146 [313, [convert_module_names]],
3149 [316, [convert_subfig]],
3152 [319, [convert_spaceinset, convert_hfill]],
3154 [321, [convert_tablines]],
3155 [322, [convert_plain_layout]],
3156 [323, [convert_pagebreaks]],
3157 [324, [convert_linebreaks]],
3158 [325, [convert_japanese_plain]],
3161 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3164 [331, [convert_ltcaption]],
3166 [333, [update_apa_styles]],
3167 [334, [convert_paper_sizes]],
3168 [335, [convert_InsetSpace]],
3170 [337, [convert_display_enum]],
3173 [340, [add_plain_layout]],
3176 [343, [convert_default_options]],
3177 [344, [convert_backref_options]],
3178 [345, [convert_charstyle_element]]
3181 revert = [[344, [revert_charstyle_element]],
3182 [343, [revert_backref_options]],
3183 [342, [revert_default_options]],
3184 [341, [revert_mongolian]],
3185 [340, [revert_tabulators, revert_tabsize]],
3187 [338, [revert_removed_modules]],
3188 [337, [revert_polytonicgreek]],
3189 [336, [revert_display_enum]],
3190 [335, [remove_fontsCJK]],
3191 [334, [revert_InsetSpace]],
3192 [333, [revert_paper_sizes]],
3194 [331, [revert_graphics_group]],
3195 [330, [revert_ltcaption]],
3196 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
3197 [328, [revert_master]],
3199 [326, [revert_mexican]],
3200 [325, [revert_pdfpages]],
3202 [323, [revert_linebreaks]],
3203 [322, [revert_pagebreaks]],
3204 [321, [revert_local_layout, revert_plain_layout]],
3205 [320, [revert_tablines]],
3206 [319, [revert_protected_hfill]],
3207 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3208 [317, [remove_extra_embedded_files]],
3209 [316, [revert_wrapplacement]],
3210 [315, [revert_subfig]],
3211 [314, [revert_colsep, revert_plainlayout]],
3213 [312, [revert_module_names]],
3214 [311, [revert_rotfloat, revert_widesideways]],
3215 [310, [revert_external_embedding]],
3216 [309, [revert_btprintall]],
3217 [308, [revert_nocite]],
3218 [307, [revert_serbianlatin]],
3219 [306, [revert_slash, revert_nobreakdash]],
3220 [305, [revert_interlingua]],
3221 [304, [revert_bahasam]],
3222 [303, [revert_framed_notes]],
3224 [301, [revert_latin, revert_samin]],
3225 [300, [revert_linebreak]],
3226 [299, [revert_pagebreak]],
3227 [298, [revert_hyperlinktype]],
3228 [297, [revert_macro_optional_params]],
3229 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3230 [295, [revert_include]],
3231 [294, [revert_href, revert_url]],
3232 [293, [revert_pdf_options_2]],
3233 [292, [revert_inset_info]],
3234 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3235 [290, [revert_vietnamese]],
3236 [289, [revert_wraptable]],
3237 [288, [revert_latexcommand_index]],
3238 [287, [revert_inset_command]],
3239 [286, [revert_wrapfig_options]],
3240 [285, [revert_pdf_options]],
3241 [284, [remove_inzip_options]],
3243 [282, [revert_flex]],
3245 [280, [revert_begin_modules]],
3246 [279, [revert_show_label]],
3247 [278, [revert_long_charstyle_names]],
3253 if __name__ == "__main__":