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
1081 j = find_end_of_inset(document.body, i + 1)
1083 document.warning("Unable to find end of index inset at line " + str(i) + "!")
1086 m = r1.match(document.body[i + 2])
1088 document.warning("Unable to match: " + document.body[i+2])
1089 # this can happen with empty index insets!
1092 fullcontent = m.group(1)
1093 linelist = latex2lyx(fullcontent)
1094 #document.warning(fullcontent)
1096 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1097 linelist + ["\\end_layout"]
1098 document.body[i : j] = linelist
1099 i += len(linelist) - (j - i)
1102 def revert_latexcommand_index(document):
1103 "Revert from collapsable form to LatexCommand form."
1106 i = find_token(document.body, "\\begin_inset Index", i)
1109 j = find_end_of_inset(document.body, i + 1)
1113 content = lyx2latex(document, document.body[i:j])
1115 content = content.replace('"', r'\"')
1116 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1117 "name " + '"' + content + '"', ""]
1121 def revert_wraptable(document):
1122 "Revert wrap table to wrap figure."
1125 i = find_token(document.body, "\\begin_inset Wrap table", i)
1128 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1132 def revert_vietnamese(document):
1133 "Set language Vietnamese to English"
1134 # Set document language from Vietnamese to English
1136 if document.language == "vietnamese":
1137 document.language = "english"
1138 i = find_token(document.header, "\\language", 0)
1140 document.header[i] = "\\language english"
1143 j = find_token(document.body, "\\lang vietnamese", j)
1146 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1150 def convert_japanese_cjk(document):
1151 "Set language japanese to japanese-cjk"
1152 # Set document language from japanese-plain to japanese
1154 if document.language == "japanese":
1155 document.language = "japanese-cjk"
1156 i = find_token(document.header, "\\language", 0)
1158 document.header[i] = "\\language japanese-cjk"
1161 j = find_token(document.body, "\\lang japanese", j)
1164 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1168 def revert_japanese(document):
1169 "Set language japanese-plain to japanese"
1170 # Set document language from japanese-plain to japanese
1172 if document.language == "japanese-plain":
1173 document.language = "japanese"
1174 i = find_token(document.header, "\\language", 0)
1176 document.header[i] = "\\language japanese"
1179 j = find_token(document.body, "\\lang japanese-plain", j)
1182 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1186 def revert_japanese_cjk(document):
1187 "Set language japanese-cjk to japanese"
1188 # Set document language from japanese-plain to japanese
1190 if document.language == "japanese-cjk":
1191 document.language = "japanese"
1192 i = find_token(document.header, "\\language", 0)
1194 document.header[i] = "\\language japanese"
1197 j = find_token(document.body, "\\lang japanese-cjk", j)
1200 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1204 def revert_japanese_encoding(document):
1205 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1206 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1208 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1210 document.header[i] = "\\inputencoding EUC-JP"
1212 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1214 document.header[j] = "\\inputencoding JIS"
1216 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1217 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1218 document.header[k] = "\\inputencoding UTF8"
1221 def revert_inset_info(document):
1222 'Replace info inset with its content'
1225 i = find_token(document.body, '\\begin_inset Info', i)
1228 j = find_end_of_inset(document.body, i + 1)
1231 document.warning("Malformed LyX document: Could not find end of Info inset.")
1234 for k in range(i, j+1):
1235 if document.body[k].startswith("arg"):
1236 arg = document.body[k][3:].strip()
1237 # remove embracing quotation marks
1240 if arg[len(arg) - 1] == '"':
1241 arg = arg[:len(arg) - 1]
1242 # \" to straight quote
1243 arg = arg.replace(r'\"','"')
1244 if document.body[k].startswith("type"):
1245 type = document.body[k][4:].strip().strip('"')
1246 # I think there is a newline after \\end_inset, which should be removed.
1247 if document.body[j + 1].strip() == "":
1248 document.body[i : (j + 2)] = [type + ':' + arg]
1250 document.body[i : (j + 1)] = [type + ':' + arg]
1253 def convert_pdf_options(document):
1254 # Set the pdfusetitle tag, delete the pdf_store_options,
1255 # set quotes for bookmarksopenlevel"
1256 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1258 k = find_token(document.header, "\\use_hyperref", 0)
1259 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1260 k = find_token(document.header, "\\pdf_store_options", 0)
1262 del document.header[k]
1263 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1265 document.header[i] = document.header[i].replace('"', '')
1268 def revert_pdf_options_2(document):
1269 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1270 k = find_token(document.header, "\\use_hyperref", 0)
1271 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1273 del document.header[i]
1274 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1276 values = document.header[i].split()
1277 values[1] = ' "' + values[1] + '"'
1278 document.header[i] = ''.join(values)
1281 def convert_htmlurl(document):
1282 'Convert "htmlurl" to "href" insets for docbook'
1283 if document.backend != "docbook":
1287 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1290 document.body[i] = "\\begin_inset CommandInset href"
1291 document.body[i + 1] = "LatexCommand href"
1295 def convert_url(document):
1296 'Convert url insets to url charstyles'
1297 if document.backend == "docbook":
1301 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1304 n = find_token(document.body, "name", i)
1306 # place the URL name in typewriter before the new URL insert
1307 # grab the name 'bla' from the e.g. the line 'name "bla"',
1308 # therefore start with the 6th character
1309 name = document.body[n][6:-1]
1310 newname = [name + " "]
1311 document.body[i:i] = newname
1313 j = find_token(document.body, "target", i)
1315 document.warning("Malformed LyX document: Can't find target for url inset")
1318 target = document.body[j][8:-1]
1319 k = find_token(document.body, "\\end_inset", j)
1321 document.warning("Malformed LyX document: Can't find end of url inset")
1324 newstuff = ["\\begin_inset Flex URL",
1325 "status collapsed", "",
1326 "\\begin_layout Standard",
1331 document.body[i:k] = newstuff
1334 def convert_ams_classes(document):
1335 tc = document.textclass
1336 if (tc != "amsart" and tc != "amsart-plain" and
1337 tc != "amsart-seq" and tc != "amsbook"):
1339 if tc == "amsart-plain":
1340 document.textclass = "amsart"
1341 document.set_textclass()
1342 document.add_module("Theorems (Starred)")
1344 if tc == "amsart-seq":
1345 document.textclass = "amsart"
1346 document.set_textclass()
1347 document.add_module("Theorems (AMS)")
1349 #Now we want to see if any of the environments in the extended theorems
1350 #module were used in this document. If so, we'll add that module, too.
1351 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1352 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1355 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1358 i = find_token(document.body, "\\begin_layout", i)
1361 m = r.match(document.body[i])
1363 # This is an empty layout
1364 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1368 if layouts.count(m) != 0:
1369 document.add_module("Theorems (AMS-Extended)")
1373 def revert_href(document):
1374 'Reverts hyperlink insets (href) to url insets (url)'
1377 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1380 document.body[i : i + 2] = \
1381 ["\\begin_inset CommandInset url", "LatexCommand url"]
1384 def revert_url(document):
1385 'Reverts Flex URL insets to old-style URL insets'
1388 i = find_token(document.body, "\\begin_inset Flex URL", i)
1391 j = find_end_of_inset(document.body, i)
1393 document.warning("Can't find end of inset in revert_url!")
1395 k = find_default_layout(document, i, j)
1397 document.warning("Can't find default layout in revert_url!")
1400 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1401 if l == -1 or l >= j:
1402 document.warning("Can't find end of default layout in revert_url!")
1405 # OK, so the inset's data is between lines k and l.
1406 data = " ".join(document.body[k+1:l])
1408 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1410 document.body[i:j+1] = newinset
1411 i = i + len(newinset)
1414 def convert_include(document):
1415 'Converts include insets to new format.'
1417 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1419 i = find_token(document.body, "\\begin_inset Include", i)
1422 line = document.body[i]
1423 previewline = document.body[i + 1]
1426 document.warning("Unable to match line " + str(i) + " of body!")
1432 insertion = ["\\begin_inset CommandInset include",
1433 "LatexCommand " + cmd, previewline,
1434 "filename \"" + fn + "\""]
1437 insertion.append("lstparams " + '"' + opt + '"')
1439 document.body[i : i + 2] = insertion
1443 def revert_include(document):
1444 'Reverts include insets to old format.'
1446 r0 = re.compile('preview.*')
1447 r1 = re.compile('LatexCommand (.+)')
1448 r2 = re.compile('filename "(.+)"')
1449 r3 = re.compile('lstparams "(.*)"')
1451 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1455 m = r1.match(document.body[nextline])
1457 document.warning("Malformed LyX document: No LatexCommand line for `" +
1458 document.body[i] + "' on line " + str(i) + ".")
1463 if r0.match(document.body[nextline]):
1464 previewline = document.body[nextline]
1468 m = r2.match(document.body[nextline])
1470 document.warning("Malformed LyX document: No filename line for `" + \
1471 document.body[i] + "' on line " + str(i) + ".")
1477 if (cmd == "lstinputlisting"):
1478 m = r3.match(document.body[nextline])
1480 options = m.group(1)
1483 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1485 newline += ("[" + options + "]")
1486 insertion = [newline]
1487 if previewline != "":
1488 insertion.append(previewline)
1489 document.body[i : nextline] = insertion
1493 def revert_albanian(document):
1494 "Set language Albanian to English"
1496 if document.language == "albanian":
1497 document.language = "english"
1498 i = find_token(document.header, "\\language", 0)
1500 document.header[i] = "\\language english"
1503 j = find_token(document.body, "\\lang albanian", j)
1506 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1510 def revert_lowersorbian(document):
1511 "Set language lower Sorbian to English"
1513 if document.language == "lowersorbian":
1514 document.language = "english"
1515 i = find_token(document.header, "\\language", 0)
1517 document.header[i] = "\\language english"
1520 j = find_token(document.body, "\\lang lowersorbian", j)
1523 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1527 def revert_uppersorbian(document):
1528 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1530 if document.language == "uppersorbian":
1531 document.language = "usorbian"
1532 i = find_token(document.header, "\\language", 0)
1534 document.header[i] = "\\language usorbian"
1537 j = find_token(document.body, "\\lang uppersorbian", j)
1540 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1544 def convert_usorbian(document):
1545 "Set language usorbian to uppersorbian"
1547 if document.language == "usorbian":
1548 document.language = "uppersorbian"
1549 i = find_token(document.header, "\\language", 0)
1551 document.header[i] = "\\language uppersorbian"
1554 j = find_token(document.body, "\\lang usorbian", j)
1557 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1561 def convert_macro_global(document):
1562 "Remove TeX code command \global when it is in front of a macro"
1563 # math macros are nowadays already defined \global, so that an additional
1564 # \global would make the document uncompilable, see
1565 # http://bugzilla.lyx.org/show_bug.cgi?id=5371
1566 # We're looking for something like this:
1570 # \begin_layout Plain Layout
1580 # \begin_inset FormulaMacro
1581 # \renewcommand{\foo}{123}
1585 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1588 # if i <= 13, then there isn't enough room for the ERT
1592 if document.body[i-6] == "global":
1593 del document.body[i-13 : i]
1599 def revert_macro_optional_params(document):
1600 "Convert macro definitions with optional parameters into ERTs"
1601 # Stub to convert macro definitions with one or more optional parameters
1602 # into uninterpreted ERT insets
1605 def revert_hyperlinktype(document):
1606 'Reverts hyperlink type'
1610 i = find_token(document.body, "target", i)
1613 j = find_token(document.body, "type", i)
1617 del document.body[j]
1621 def revert_pagebreak(document):
1622 'Reverts pagebreak to ERT'
1625 i = find_token(document.body, "\\pagebreak", i)
1628 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1629 '\\begin_layout Standard\n\n\n\\backslash\n' \
1630 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1634 def revert_linebreak(document):
1635 'Reverts linebreak to ERT'
1638 i = find_token(document.body, "\\linebreak", i)
1641 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1642 '\\begin_layout Standard\n\n\n\\backslash\n' \
1643 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1647 def revert_latin(document):
1648 "Set language Latin to English"
1650 if document.language == "latin":
1651 document.language = "english"
1652 i = find_token(document.header, "\\language", 0)
1654 document.header[i] = "\\language english"
1657 j = find_token(document.body, "\\lang latin", j)
1660 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1664 def revert_samin(document):
1665 "Set language North Sami to English"
1667 if document.language == "samin":
1668 document.language = "english"
1669 i = find_token(document.header, "\\language", 0)
1671 document.header[i] = "\\language english"
1674 j = find_token(document.body, "\\lang samin", j)
1677 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1681 def convert_serbocroatian(document):
1682 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1684 if document.language == "serbocroatian":
1685 document.language = "croatian"
1686 i = find_token(document.header, "\\language", 0)
1688 document.header[i] = "\\language croatian"
1691 j = find_token(document.body, "\\lang serbocroatian", j)
1694 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1698 def convert_framed_notes(document):
1699 "Convert framed notes to boxes. "
1702 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1705 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1714 'height_special "totalheight"']
1715 document.body[i:i+1] = subst
1719 def convert_module_names(document):
1720 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1721 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1722 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1723 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1724 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1725 modlist = document.get_module_list()
1726 if len(modlist) == 0:
1730 if modulemap.has_key(mod):
1731 newmodlist.append(modulemap[mod])
1733 document.warning("Can't find module %s in the module map!" % mod)
1734 newmodlist.append(mod)
1735 document.set_module_list(newmodlist)
1738 def revert_module_names(document):
1739 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1740 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1741 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1742 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1743 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1744 modlist = document.get_module_list()
1745 if len(modlist) == 0:
1749 if modulemap.has_key(mod):
1750 newmodlist.append(modulemap[mod])
1752 document.warning("Can't find module %s in the module map!" % mod)
1753 newmodlist.append(mod)
1754 document.set_module_list(newmodlist)
1757 def revert_colsep(document):
1758 i = find_token(document.header, "\\columnsep", 0)
1761 colsepline = document.header[i]
1762 r = re.compile(r'\\columnsep (.*)')
1763 m = r.match(colsepline)
1765 document.warning("Malformed column separation line!")
1768 del document.header[i]
1769 #it seems to be safe to add the package even if it is already used
1770 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1772 add_to_preamble(document, pretext)
1775 def revert_framed_notes(document):
1776 "Revert framed boxes to notes. "
1779 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1783 j = find_end_of_inset(document.body, i + 1)
1786 document.warning("Malformed LyX document: Could not find end of Box inset.")
1787 k = find_token(document.body, "status", i + 1, j)
1789 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1791 status = document.body[k]
1792 l = find_default_layout(document, i + 1, j)
1794 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1796 m = find_token(document.body, "\\end_layout", i + 1, j)
1798 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1800 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1801 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1802 if ibox == -1 and pbox == -1:
1803 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1804 del document.body[i+1:k]
1806 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1807 subst1 = [document.body[l],
1808 "\\begin_inset Note Shaded",
1810 '\\begin_layout Standard']
1811 document.body[l:l + 1] = subst1
1812 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1813 document.body[m:m + 1] = subst2
1817 def revert_slash(document):
1818 'Revert \\SpecialChar \\slash{} to ERT'
1820 while i < len(document.body):
1821 m = re.match(r'(.*)\\SpecialChar \\slash{}(.*)', document.body[i])
1826 '\\begin_inset ERT',
1827 'status collapsed', '',
1828 '\\begin_layout Standard',
1829 '', '', '\\backslash',
1834 document.body[i: i+1] = subst
1840 def revert_nobreakdash(document):
1841 'Revert \\SpecialChar \\nobreakdash- to ERT'
1843 while i < len(document.body):
1844 m = re.match(r'(.*)\\SpecialChar \\nobreakdash-(.*)', document.body[i])
1849 '\\begin_inset ERT',
1850 'status collapsed', '',
1851 '\\begin_layout Standard', '', '',
1857 document.body[i: i+1] = subst
1859 j = find_token(document.header, "\\use_amsmath", 0)
1861 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1863 document.header[j] = "\\use_amsmath 2"
1868 #Returns number of lines added/removed
1869 def revert_nocite_key(body, start, end):
1870 'key "..." -> \nocite{...}'
1871 r = re.compile(r'^key "(.*)"')
1875 m = r.match(body[i])
1877 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1878 j += 1 # because we added a line
1879 i += 2 # skip that line
1882 j -= 1 # because we deleted a line
1883 # no need to change i, since it now points to the next line
1887 def revert_nocite(document):
1888 "Revert LatexCommand nocite to ERT"
1891 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1894 if (document.body[i+1] != "LatexCommand nocite"):
1895 # note that we already incremented i
1898 insetEnd = find_end_of_inset(document.body, i)
1900 #this should not happen
1901 document.warning("End of CommandInset citation not found in revert_nocite!")
1904 paramLocation = i + 2 #start of the inset's parameters
1906 document.body[i:i+2] = \
1907 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1908 # that added two lines
1911 #print insetEnd, document.body[i: insetEnd + 1]
1912 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1913 #print insetEnd, document.body[i: insetEnd + 1]
1914 document.body.insert(insetEnd, "\\end_layout")
1915 document.body.insert(insetEnd + 1, "")
1919 def revert_btprintall(document):
1920 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1921 i = find_token(document.header, '\\use_bibtopic', 0)
1923 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1925 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1927 while i < len(document.body):
1928 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1931 j = find_end_of_inset(document.body, i + 1)
1933 #this should not happen
1934 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1935 j = len(document.body)
1936 # this range isn't really right, but it should be OK, since we shouldn't
1937 # see more than one matching line in each inset
1939 for k in range(i, j):
1940 if (document.body[k] == 'btprint "btPrintAll"'):
1941 del document.body[k]
1942 subst = ["\\begin_inset ERT",
1943 "status collapsed", "",
1944 "\\begin_layout Standard", "",
1949 document.body[i:i] = subst
1950 addlines = addedlines + len(subst) - 1
1954 def revert_bahasam(document):
1955 "Set language Bahasa Malaysia to Bahasa Indonesia"
1957 if document.language == "bahasam":
1958 document.language = "bahasa"
1959 i = find_token(document.header, "\\language", 0)
1961 document.header[i] = "\\language bahasa"
1964 j = find_token(document.body, "\\lang bahasam", j)
1967 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1971 def revert_interlingua(document):
1972 "Set language Interlingua to English"
1974 if document.language == "interlingua":
1975 document.language = "english"
1976 i = find_token(document.header, "\\language", 0)
1978 document.header[i] = "\\language english"
1981 j = find_token(document.body, "\\lang interlingua", j)
1984 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1988 def revert_serbianlatin(document):
1989 "Set language Serbian-Latin to Croatian"
1991 if document.language == "serbian-latin":
1992 document.language = "croatian"
1993 i = find_token(document.header, "\\language", 0)
1995 document.header[i] = "\\language croatian"
1998 j = find_token(document.body, "\\lang serbian-latin", j)
2001 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
2005 def revert_rotfloat(document):
2006 " Revert sideways custom floats. "
2009 # whitespace intended (exclude \\begin_inset FloatList)
2010 i = find_token(document.body, "\\begin_inset Float ", i)
2013 line = document.body[i]
2014 r = re.compile(r'\\begin_inset Float (.*)$')
2017 document.warning("Unable to match line " + str(i) + " of body!")
2020 floattype = m.group(1)
2021 if floattype == "figure" or floattype == "table":
2024 j = find_end_of_inset(document.body, i)
2026 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
2030 if get_value(document.body, 'sideways', i, j) == "false":
2033 l = find_default_layout(document, i + 1, j)
2035 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2037 subst = ['\\begin_layout Standard',
2038 '\\begin_inset ERT',
2039 'status collapsed', '',
2040 '\\begin_layout Standard', '', '',
2042 'end{sideways' + floattype + '}',
2043 '\\end_layout', '', '\\end_inset']
2044 document.body[j : j+1] = subst
2045 addedLines = len(subst) - 1
2046 del document.body[i+1 : l]
2047 addedLines -= (l-1) - (i+1)
2048 subst = ['\\begin_inset ERT', 'status collapsed', '',
2049 '\\begin_layout Standard', '', '', '\\backslash',
2050 'begin{sideways' + floattype + '}',
2051 '\\end_layout', '', '\\end_inset', '',
2053 document.body[i : i+1] = subst
2054 addedLines += len(subst) - 1
2055 if floattype == "algorithm":
2056 add_to_preamble(document,
2057 ['% Commands inserted by lyx2lyx for sideways algorithm float',
2058 '\\usepackage{rotfloat}',
2059 '\\floatstyle{ruled}',
2060 '\\newfloat{algorithm}{tbp}{loa}',
2061 '\\floatname{algorithm}{Algorithm}'])
2063 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
2067 def revert_widesideways(document):
2068 " Revert wide sideways floats. "
2071 # whitespace intended (exclude \\begin_inset FloatList)
2072 i = find_token(document.body, '\\begin_inset Float ', i)
2075 line = document.body[i]
2076 r = re.compile(r'\\begin_inset Float (.*)$')
2079 document.warning("Unable to match line " + str(i) + " of body!")
2082 floattype = m.group(1)
2083 if floattype != "figure" and floattype != "table":
2086 j = find_end_of_inset(document.body, i)
2088 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2091 if get_value(document.body, 'sideways', i, j) == "false" or \
2092 get_value(document.body, 'wide', i, j) == "false":
2095 l = find_default_layout(document, i + 1, j)
2097 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2099 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2100 'status collapsed', '',
2101 '\\begin_layout Standard', '', '', '\\backslash',
2102 'end{sideways' + floattype + '*}',
2103 '\\end_layout', '', '\\end_inset']
2104 document.body[j : j+1] = subst
2105 addedLines = len(subst) - 1
2106 del document.body[i+1:l-1]
2107 addedLines -= (l-1) - (i+1)
2108 subst = ['\\begin_inset ERT', 'status collapsed', '',
2109 '\\begin_layout Standard', '', '', '\\backslash',
2110 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2111 '\\end_inset', '', '\\end_layout', '']
2112 document.body[i : i+1] = subst
2113 addedLines += len(subst) - 1
2114 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2118 def revert_inset_embedding(document, type):
2119 ' Remove embed tag from certain type of insets'
2122 i = find_token(document.body, "\\begin_inset %s" % type, i)
2125 j = find_end_of_inset(document.body, i)
2127 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2130 k = find_token(document.body, "\tembed", i, j)
2132 k = find_token(document.body, "embed", i, j)
2134 del document.body[k]
2138 def revert_external_embedding(document):
2139 ' Remove embed tag from external inset '
2140 revert_inset_embedding(document, 'External')
2143 def convert_subfig(document):
2144 " Convert subfigures to subfloats. "
2148 i = find_token(document.body, '\\begin_inset Graphics', i)
2151 endInset = find_end_of_inset(document.body, i)
2153 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2156 k = find_token(document.body, '\tsubcaption', i, endInset)
2160 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2164 caption = document.body[l][16:].strip('"')
2165 del document.body[l]
2167 del document.body[k]
2169 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2170 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2171 '', '\\begin_layout Plain Layout'] + latex2lyx(caption) + \
2172 [ '\\end_layout', '', '\\end_inset', '',
2173 '\\end_layout', '', '\\begin_layout Plain Layout']
2174 document.body[i : i] = subst
2175 addedLines += len(subst)
2176 endInset += addedLines
2177 subst = ['', '\\end_inset', '', '\\end_layout']
2178 document.body[endInset : endInset] = subst
2179 addedLines += len(subst)
2183 def revert_subfig(document):
2184 " Revert subfloats. "
2187 # whitespace intended (exclude \\begin_inset FloatList)
2188 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2194 j = find_end_of_inset(document.body, i)
2196 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2197 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2199 continue # this will get us back to the outer loop, since j == -1
2200 # look for embedded float (= subfloat)
2201 # whitespace intended (exclude \\begin_inset FloatList)
2202 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2205 # is the subfloat aligned?
2206 al = find_token(document.body, '\\align ', k - 1, j)
2210 if get_value(document.body, '\\align', al) == "center":
2211 alignment_beg = "\\backslash\nbegin{centering}"
2212 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2213 elif get_value(document.body, '\\align', al) == "left":
2214 alignment_beg = "\\backslash\nbegin{raggedright}"
2215 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2216 elif get_value(document.body, '\\align', al) == "right":
2217 alignment_beg = "\\backslash\nbegin{raggedleft}"
2218 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2219 l = find_end_of_inset(document.body, k)
2221 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2224 continue # escape to the outer loop
2225 m = find_default_layout(document, k + 1, l)
2227 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2232 capend = find_end_of_inset(document.body, cap)
2234 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2238 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2240 lblend = find_end_of_inset(document.body, lbl + 1)
2242 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2244 for line in document.body[lbl:lblend + 1]:
2245 if line.startswith('name '):
2246 label = line.split()[1].strip('"')
2253 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2255 optend = find_end_of_inset(document.body, opt)
2257 document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
2259 optc = find_default_layout(document, opt, optend)
2261 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2263 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2264 for line in document.body[optc:optcend]:
2265 if not line.startswith('\\'):
2266 shortcap += line.strip()
2270 for line in document.body[cap:capend]:
2271 if line in document.body[lbl:lblend]:
2273 elif line in document.body[opt:optend]:
2275 elif not line.startswith('\\'):
2276 caption += line.strip()
2278 caption += "\\backslash\nlabel{" + label + "}"
2279 subst = '\\begin_layout Plain Layout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2280 '\\begin_layout Plain Layout\n\n}' + alignment_end + \
2281 '\n\\end_layout\n\n\\end_inset\n\n' \
2282 '\\end_layout\n\n\\begin_layout Plain Layout\n'
2283 subst = subst.split('\n')
2284 document.body[l : l+1] = subst
2285 addedLines = len(subst) - 1
2286 # this is before l and so is unchanged by the multiline insertion
2288 del document.body[cap:capend+1]
2289 addedLines -= (capend + 1 - cap)
2290 del document.body[k+1:m-1]
2291 addedLines -= (m - 1 - (k + 1))
2292 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2293 '\\begin_layout Plain Layout\n\n' + alignment_beg + '\\backslash\n' \
2295 if len(shortcap) > 0:
2296 insertion = insertion + "[" + shortcap + "]"
2297 if len(caption) > 0:
2298 insertion = insertion + "[" + caption + "]"
2299 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2300 insertion = insertion.split('\n')
2301 document.body[k : k + 1] = insertion
2302 addedLines += len(insertion) - 1
2304 del document.body[al]
2306 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2310 def revert_wrapplacement(document):
2311 " Revert placement options wrap floats (wrapfig). "
2314 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2317 e = find_end_of_inset(document.body, i)
2318 j = find_token(document.body, "placement", i + 1, e)
2320 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2323 r = re.compile("placement (o|i|l|r|O|I|L|R)")
2324 m = r.match(document.body[j])
2326 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2328 document.body[j] = "placement " + m.group(1).lower()
2332 def remove_extra_embedded_files(document):
2333 " Remove \extra_embedded_files from buffer params "
2334 i = find_token(document.header, '\\extra_embedded_files', 0)
2337 document.header.pop(i)
2340 def convert_spaceinset(document):
2341 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2343 while i < len(document.body):
2344 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2348 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2349 document.body[i: i+1] = subst
2355 def revert_spaceinset(document):
2356 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2359 i = find_token(document.body, "\\begin_inset Space", i)
2362 j = find_end_of_inset(document.body, i)
2364 document.warning("Malformed LyX document: Could not find end of space inset.")
2366 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2367 del document.body[j]
2370 def convert_hfill(document):
2371 " Convert hfill to space inset "
2374 i = find_token(document.body, "\\hfill", i)
2377 subst = document.body[i].replace('\\hfill', \
2378 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2379 subst = subst.split('\n')
2380 document.body[i : i+1] = subst
2384 def revert_hfills(document):
2385 ' Revert \\hfill commands '
2386 hfill = re.compile(r'\\hfill')
2387 dotfill = re.compile(r'\\dotfill')
2388 hrulefill = re.compile(r'\\hrulefill')
2391 i = find_token(document.body, "\\InsetSpace", i)
2394 if hfill.search(document.body[i]):
2395 document.body[i] = \
2396 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2399 if dotfill.search(document.body[i]):
2400 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2401 '\\begin_inset ERT\nstatus collapsed\n\n' \
2402 '\\begin_layout Standard\n\n\n\\backslash\n' \
2403 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2404 subst = subst.split('\n')
2405 document.body[i : i+1] = subst
2408 if hrulefill.search(document.body[i]):
2409 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2410 '\\begin_inset ERT\nstatus collapsed\n\n' \
2411 '\\begin_layout Standard\n\n\n\\backslash\n' \
2412 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2413 subst = subst.split('\n')
2414 document.body[i : i+1] = subst
2419 def revert_hspace(document):
2420 ' Revert \\InsetSpace \\hspace{} to ERT '
2422 hspace = re.compile(r'\\hspace{}')
2423 hstar = re.compile(r'\\hspace\*{}')
2425 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2428 length = get_value(document.body, '\\length', i+1)
2430 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2432 del document.body[i+1]
2434 if hstar.search(document.body[i]):
2435 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2436 '\\begin_inset ERT\nstatus collapsed\n\n' \
2437 '\\begin_layout Standard\n\n\n\\backslash\n' \
2438 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2439 subst = subst.split('\n')
2440 document.body[i : i+1] = subst
2441 addedLines += len(subst) - 1
2444 if hspace.search(document.body[i]):
2445 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2446 '\\begin_inset ERT\nstatus collapsed\n\n' \
2447 '\\begin_layout Standard\n\n\n\\backslash\n' \
2448 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2449 subst = subst.split('\n')
2450 document.body[i : i+1] = subst
2451 addedLines += len(subst) - 1
2457 def revert_protected_hfill(document):
2458 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2461 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2464 j = find_end_of_inset(document.body, i)
2466 document.warning("Malformed LyX document: Could not find end of space inset.")
2468 del document.body[j]
2469 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2470 '\\begin_inset ERT\nstatus collapsed\n\n' \
2471 '\\begin_layout Standard\n\n\n\\backslash\n' \
2472 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2473 subst = subst.split('\n')
2474 document.body[i : i+1] = subst
2478 def revert_leftarrowfill(document):
2479 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2482 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2485 j = find_end_of_inset(document.body, i)
2487 document.warning("Malformed LyX document: Could not find end of space inset.")
2489 del document.body[j]
2490 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2491 '\\begin_inset ERT\nstatus collapsed\n\n' \
2492 '\\begin_layout Standard\n\n\n\\backslash\n' \
2493 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2494 subst = subst.split('\n')
2495 document.body[i : i+1] = subst
2499 def revert_rightarrowfill(document):
2500 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2503 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2506 j = find_end_of_inset(document.body, i)
2508 document.warning("Malformed LyX document: Could not find end of space inset.")
2510 del document.body[j]
2511 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2512 '\\begin_inset ERT\nstatus collapsed\n\n' \
2513 '\\begin_layout Standard\n\n\n\\backslash\n' \
2514 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2515 subst = subst.split('\n')
2516 document.body[i : i+1] = subst
2520 def revert_upbracefill(document):
2521 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2524 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2527 j = find_end_of_inset(document.body, i)
2529 document.warning("Malformed LyX document: Could not find end of space inset.")
2531 del document.body[j]
2532 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2533 '\\begin_inset ERT\nstatus collapsed\n\n' \
2534 '\\begin_layout Standard\n\n\n\\backslash\n' \
2535 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2536 subst = subst.split('\n')
2537 document.body[i : i+1] = subst
2541 def revert_downbracefill(document):
2542 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2545 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2548 j = find_end_of_inset(document.body, i)
2550 document.warning("Malformed LyX document: Could not find end of space inset.")
2552 del document.body[j]
2553 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2554 '\\begin_inset ERT\nstatus collapsed\n\n' \
2555 '\\begin_layout Standard\n\n\n\\backslash\n' \
2556 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2557 subst = subst.split('\n')
2558 document.body[i : i+1] = subst
2562 def revert_local_layout(document):
2563 ' Revert local layout headers.'
2566 i = find_token(document.header, "\\begin_local_layout", i)
2569 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2571 # this should not happen
2573 document.header[i : j + 1] = []
2576 def convert_pagebreaks(document):
2577 ' Convert inline Newpage insets to new format '
2580 i = find_token(document.body, '\\newpage', i)
2583 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2587 i = find_token(document.body, '\\pagebreak', i)
2590 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2594 i = find_token(document.body, '\\clearpage', i)
2597 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2601 i = find_token(document.body, '\\cleardoublepage', i)
2604 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2608 def revert_pagebreaks(document):
2609 ' Revert \\begin_inset Newpage to previous inline format '
2612 i = find_token(document.body, '\\begin_inset Newpage', i)
2615 j = find_end_of_inset(document.body, i)
2617 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2619 del document.body[j]
2620 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2621 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2622 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2623 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2626 def convert_linebreaks(document):
2627 ' Convert inline Newline insets to new format '
2630 i = find_token(document.body, '\\newline', i)
2633 document.body[i:i+1] = ['\\begin_inset Newline newline',
2637 i = find_token(document.body, '\\linebreak', i)
2640 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2644 def revert_linebreaks(document):
2645 ' Revert \\begin_inset Newline to previous inline format '
2648 i = find_token(document.body, '\\begin_inset Newline', i)
2651 j = find_end_of_inset(document.body, i)
2653 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2655 del document.body[j]
2656 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2657 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2660 def convert_japanese_plain(document):
2661 ' Set language japanese-plain to japanese '
2663 if document.language == "japanese-plain":
2664 document.language = "japanese"
2665 i = find_token(document.header, "\\language", 0)
2667 document.header[i] = "\\language japanese"
2670 j = find_token(document.body, "\\lang japanese-plain", j)
2673 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2677 def revert_pdfpages(document):
2678 ' Revert pdfpages external inset to ERT '
2681 i = find_token(document.body, "\\begin_inset External", i)
2684 j = find_end_of_inset(document.body, i)
2686 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2689 if get_value(document.body, 'template', i, j) == "PDFPages":
2690 filename = get_value(document.body, 'filename', i, j)
2692 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2693 for k in range(i, j):
2694 m = r.match(document.body[k])
2697 angle = get_value(document.body, 'rotateAngle', i, j)
2698 width = get_value(document.body, 'width', i, j)
2699 height = get_value(document.body, 'height', i, j)
2700 scale = get_value(document.body, 'scale', i, j)
2701 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2705 options += ",angle=" + angle
2707 options += "angle=" + angle
2710 options += ",width=" + convert_len(width)
2712 options += "width=" + convert_len(width)
2715 options += ",height=" + convert_len(height)
2717 options += "height=" + convert_len(height)
2720 options += ",scale=" + scale
2722 options += "scale=" + scale
2723 if keepAspectRatio != '':
2725 options += ",keepaspectratio"
2727 options += "keepaspectratio"
2729 options = '[' + options + ']'
2730 del document.body[i+1:j+1]
2731 document.body[i:i+1] = ['\\begin_inset ERT',
2734 '\\begin_layout Standard',
2737 'includepdf' + options + '{' + filename + '}',
2741 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2747 def revert_mexican(document):
2748 ' Set language Spanish(Mexico) to Spanish '
2750 if document.language == "spanish-mexico":
2751 document.language = "spanish"
2752 i = find_token(document.header, "\\language", 0)
2754 document.header[i] = "\\language spanish"
2757 j = find_token(document.body, "\\lang spanish-mexico", j)
2760 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2764 def remove_embedding(document):
2765 ' Remove embed tag from all insets '
2766 revert_inset_embedding(document, 'Graphics')
2767 revert_inset_embedding(document, 'External')
2768 revert_inset_embedding(document, 'CommandInset include')
2769 revert_inset_embedding(document, 'CommandInset bibtex')
2772 def revert_master(document):
2773 ' Remove master param '
2774 i = find_token(document.header, "\\master", 0)
2776 del document.header[i]
2779 def revert_graphics_group(document):
2780 ' Revert group information from graphics insets '
2783 i = find_token(document.body, "\\begin_inset Graphics", i)
2786 j = find_end_of_inset(document.body, i)
2788 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2791 k = find_token(document.body, " groupId", i, j)
2795 del document.body[k]
2799 def update_apa_styles(document):
2800 ' Replace obsolete styles '
2802 if document.textclass != "apa":
2805 obsoletedby = { "Acknowledgments": "Acknowledgements",
2806 "Section*": "Section",
2807 "Subsection*": "Subsection",
2808 "Subsubsection*": "Subsubsection",
2809 "Paragraph*": "Paragraph",
2810 "Subparagraph*": "Subparagraph"}
2813 i = find_token(document.body, "\\begin_layout", i)
2817 layout = document.body[i][14:]
2818 if layout in obsoletedby:
2819 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2824 def convert_paper_sizes(document):
2825 ' exchange size options legalpaper and executivepaper to correct order '
2826 # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2829 i = find_token(document.header, "\\papersize executivepaper", 0)
2831 document.header[i] = "\\papersize legalpaper"
2833 j = find_token(document.header, "\\papersize legalpaper", 0)
2835 document.header[j] = "\\papersize executivepaper"
2838 def revert_paper_sizes(document):
2839 ' exchange size options legalpaper and executivepaper to correct order '
2842 i = find_token(document.header, "\\papersize executivepaper", 0)
2844 document.header[i] = "\\papersize legalpaper"
2846 j = find_token(document.header, "\\papersize legalpaper", 0)
2848 document.header[j] = "\\papersize executivepaper"
2851 def convert_InsetSpace(document):
2852 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2855 i = find_token(document.body, "\\begin_inset Space", i)
2858 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2861 def revert_InsetSpace(document):
2862 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2865 i = find_token(document.body, "\\begin_inset space", i)
2868 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2871 def convert_display_enum(document):
2872 " Convert 'display foo' to 'display false/true'"
2875 i = find_token(document.body, "\tdisplay", i)
2878 val = get_value(document.body, 'display', i)
2880 document.body[i] = document.body[i].replace('none', 'false')
2881 if val == "default":
2882 document.body[i] = document.body[i].replace('default', 'true')
2883 if val == "monochrome":
2884 document.body[i] = document.body[i].replace('monochrome', 'true')
2885 if val == "grayscale":
2886 document.body[i] = document.body[i].replace('grayscale', 'true')
2888 document.body[i] = document.body[i].replace('color', 'true')
2889 if val == "preview":
2890 document.body[i] = document.body[i].replace('preview', 'true')
2894 def revert_display_enum(document):
2895 " Revert 'display false/true' to 'display none/color'"
2898 i = find_token(document.body, "\tdisplay", i)
2901 val = get_value(document.body, 'display', i)
2903 document.body[i] = document.body[i].replace('false', 'none')
2905 document.body[i] = document.body[i].replace('true', 'default')
2909 def remove_fontsCJK(document):
2910 ' Remove font_cjk param '
2911 i = find_token(document.header, "\\font_cjk", 0)
2913 del document.header[i]
2916 def convert_plain_layout(document):
2917 " Convert 'PlainLayout' to 'Plain Layout'"
2920 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2923 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2924 '\\begin_layout Plain Layout')
2928 def revert_plain_layout(document):
2929 " Convert 'PlainLayout' to 'Plain Layout'"
2932 i = find_token(document.body, '\\begin_layout Plain Layout', i)
2935 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2936 '\\begin_layout PlainLayout')
2940 def revert_plainlayout(document):
2941 " Convert 'PlainLayout' to 'Plain Layout'"
2944 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2947 # This will be incorrect for some document classes, since Standard is not always
2948 # the default. But (a) it is probably the best we can do and (b) it will actually
2949 # work, in fact, since an unknown layout will be converted to default.
2950 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2951 '\\begin_layout Standard')
2955 def revert_polytonicgreek(document):
2956 "Set language polytonic Greek to Greek"
2958 if document.language == "polutonikogreek":
2959 document.language = "greek"
2960 i = find_token(document.header, "\\language", 0)
2962 document.header[i] = "\\language greek"
2965 j = find_token(document.body, "\\lang polutonikogreek", j)
2968 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2972 def revert_removed_modules(document):
2975 i = find_token(document.header, "\\begin_remove_modules", i)
2978 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
2980 # this should not happen
2982 document.header[i : j + 1] = []
2985 def add_plain_layout(document):
2988 i = find_token(document.body, "\\begin_layout", i)
2991 if len(document.body[i].split()) == 1:
2992 document.body[i] = "\\begin_layout Plain Layout"
2996 def revert_tabulators(document):
2997 "Revert tabulators to 4 spaces"
3000 i = find_token(document.body, "\t", i)
3003 document.body[i] = document.body[i].replace("\t", " ")
3007 def revert_tabsize(document):
3008 "Revert the tabsize parameter of listings"
3012 # either it is the only parameter
3013 i = find_token(document.body, 'lstparams "tabsize=4"', i)
3015 del document.body[i]
3017 j = find_token(document.body, "lstparams", j)
3020 pos = document.body[j].find(",tabsize=")
3021 document.body[j] = document.body[j][:pos] + '"'
3026 def revert_mongolian(document):
3027 "Set language Mongolian to English"
3029 if document.language == "mongolian":
3030 document.language = "english"
3031 i = find_token(document.header, "\\language", 0)
3033 document.header[i] = "\\language english"
3036 j = find_token(document.body, "\\lang mongolian", j)
3039 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
3043 def revert_default_options(document):
3044 ' Remove param use_default_options '
3045 i = find_token(document.header, "\\use_default_options", 0)
3047 del document.header[i]
3050 def convert_default_options(document):
3051 ' Add param use_default_options and set it to false '
3052 i = find_token(document.header, "\\textclass", 0)
3054 document.warning("Malformed LyX document: Missing `\\textclass'.")
3056 document.header.insert(i, '\\use_default_options false')
3059 def revert_backref_options(document):
3060 ' Revert option pdf_backref=page to pagebackref '
3061 i = find_token(document.header, "\\pdf_backref page", 0)
3063 document.header[i] = "\\pdf_pagebackref true"
3066 def convert_backref_options(document):
3067 ' We have changed the option pagebackref to backref=true '
3068 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3070 document.header[i] = "\\pdf_backref page"
3071 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3073 del document.header[j]
3074 # backref=true was not a valid option, we meant backref=section
3075 k = find_token(document.header, "\\pdf_backref true", 0)
3076 if k != -1 and i != -1:
3077 del document.header[k]
3078 elif k != -1 and j != -1:
3079 document.header[k] = "\\pdf_backref section"
3082 def convert_charstyle_element(document):
3083 "Convert CharStyle to Element for docbook backend"
3084 if document.backend != "docbook":
3088 i = find_token(document.body, "\\begin_inset Flex CharStyle:", i)
3091 document.body[i] = document.body[i].replace('\\begin_inset Flex CharStyle:',
3092 '\\begin_inset Flex Element:')
3094 def revert_charstyle_element(document):
3095 "Convert Element to CharStyle for docbook backend"
3096 if document.backend != "docbook":
3100 i = find_token(document.body, "\\begin_inset Flex Element:", i)
3103 document.body[i] = document.body[i].replace('\\begin_inset Flex Element:',
3104 '\\begin_inset Flex CharStyle:')
3110 supported_versions = ["1.6.0","1.6"]
3111 convert = [[277, [fix_wrong_tables]],
3112 [278, [close_begin_deeper]],
3113 [279, [long_charstyle_names]],
3114 [280, [axe_show_label]],
3117 [283, [convert_flex]],
3121 [287, [convert_wrapfig_options]],
3122 [288, [convert_inset_command]],
3123 [289, [convert_latexcommand_index]],
3126 [292, [convert_japanese_cjk]],
3128 [294, [convert_pdf_options]],
3129 [295, [convert_htmlurl, convert_url]],
3130 [296, [convert_include]],
3131 [297, [convert_usorbian]],
3132 [298, [convert_macro_global]],
3137 [303, [convert_serbocroatian]],
3138 [304, [convert_framed_notes]],
3145 [311, [convert_ams_classes]],
3147 [313, [convert_module_names]],
3150 [316, [convert_subfig]],
3153 [319, [convert_spaceinset, convert_hfill]],
3155 [321, [convert_tablines]],
3156 [322, [convert_plain_layout]],
3157 [323, [convert_pagebreaks]],
3158 [324, [convert_linebreaks]],
3159 [325, [convert_japanese_plain]],
3162 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3165 [331, [convert_ltcaption]],
3167 [333, [update_apa_styles]],
3168 [334, [convert_paper_sizes]],
3169 [335, [convert_InsetSpace]],
3171 [337, [convert_display_enum]],
3174 [340, [add_plain_layout]],
3177 [343, [convert_default_options]],
3178 [344, [convert_backref_options]],
3179 [345, [convert_charstyle_element]]
3182 revert = [[344, [revert_charstyle_element]],
3183 [343, [revert_backref_options]],
3184 [342, [revert_default_options]],
3185 [341, [revert_mongolian]],
3186 [340, [revert_tabulators, revert_tabsize]],
3188 [338, [revert_removed_modules]],
3189 [337, [revert_polytonicgreek]],
3190 [336, [revert_display_enum]],
3191 [335, [remove_fontsCJK]],
3192 [334, [revert_InsetSpace]],
3193 [333, [revert_paper_sizes]],
3195 [331, [revert_graphics_group]],
3196 [330, [revert_ltcaption]],
3197 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
3198 [328, [revert_master]],
3200 [326, [revert_mexican]],
3201 [325, [revert_pdfpages]],
3203 [323, [revert_linebreaks]],
3204 [322, [revert_pagebreaks]],
3205 [321, [revert_local_layout, revert_plain_layout]],
3206 [320, [revert_tablines]],
3207 [319, [revert_protected_hfill]],
3208 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3209 [317, [remove_extra_embedded_files]],
3210 [316, [revert_wrapplacement]],
3211 [315, [revert_subfig]],
3212 [314, [revert_colsep, revert_plainlayout]],
3214 [312, [revert_module_names]],
3215 [311, [revert_rotfloat, revert_widesideways]],
3216 [310, [revert_external_embedding]],
3217 [309, [revert_btprintall]],
3218 [308, [revert_nocite]],
3219 [307, [revert_serbianlatin]],
3220 [306, [revert_slash, revert_nobreakdash]],
3221 [305, [revert_interlingua]],
3222 [304, [revert_bahasam]],
3223 [303, [revert_framed_notes]],
3225 [301, [revert_latin, revert_samin]],
3226 [300, [revert_linebreak]],
3227 [299, [revert_pagebreak]],
3228 [298, [revert_hyperlinktype]],
3229 [297, [revert_macro_optional_params]],
3230 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3231 [295, [revert_include]],
3232 [294, [revert_href, revert_url]],
3233 [293, [revert_pdf_options_2]],
3234 [292, [revert_inset_info]],
3235 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3236 [290, [revert_vietnamese]],
3237 [289, [revert_wraptable]],
3238 [288, [revert_latexcommand_index]],
3239 [287, [revert_inset_command]],
3240 [286, [revert_wrapfig_options]],
3241 [285, [revert_pdf_options]],
3242 [284, [remove_inzip_options]],
3244 [282, [revert_flex]],
3246 [280, [revert_begin_modules]],
3247 [279, [revert_show_label]],
3248 [278, [revert_long_charstyle_names]],
3254 if __name__ == "__main__":