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
27 ####################################################################
28 # Private helper functions
31 def get_value_string(lines, token, start, end = 0, trim = False, default = ""):
32 """ get_value_string(lines, token, start[[, end], trim, default]) -> string
34 Return tokens after token as string, in lines, where
35 token is the first element. When trim is used, the first and last character
36 of the string is trimmed."""
38 val = get_value(lines, token, start, end, "")
46 def find_end_of_inset(lines, i):
47 " Find end of inset, where lines[i] is included."
48 return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
52 # document.body[i] = wrap_insert_ert(...)
53 # wrap_into_ert may returns a multiline string, which should NOT appear
54 # in document.body. Insetad, do something like this:
55 # subst = wrap_inset_ert(...)
56 # subst = subst.split('\n')
57 # document.body[i:i+1] = subst
59 # where the last statement resets the counter to accord with the added
61 def wrap_into_ert(string, src, dst):
62 '''Within string, replace occurrences of src with dst, wrapped into ERT
63 E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is:
64 sch<ERT>\\backslash</ERT>"on'''
65 return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
66 + dst + '\n\\end_layout\n\\end_inset\n')
68 def put_cmd_in_ert(string):
69 for rep in unicode_reps:
70 string = string.replace(rep[1], rep[0].replace('\\\\', '\\'))
71 string = string.replace('\\', "\\backslash\n")
72 string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n" \
73 + string + "\n\\end_layout\n\\end_inset"
76 def add_to_preamble(document, text):
77 """ Add text to the preamble if it is not already there.
78 Only the first line is checked!"""
80 if find_token(document.preamble, text[0], 0) != -1:
83 document.preamble.extend(text)
85 def insert_to_preamble(index, document, text):
86 """ Insert text to the preamble at a given line"""
88 document.preamble.insert(index, text)
90 # Convert a LyX length into a LaTeX length
92 units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
93 "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
94 "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
96 # Convert LyX units to LaTeX units
97 for unit in units.keys():
98 if len.find(unit) != -1:
99 len = '%f' % (len2value(len) / 100)
100 len = len.strip('0') + units[unit]
105 # Return the value of len without the unit in numerical form.
107 result = re.search('([+-]?[0-9.]+)', len)
109 return float(result.group(1))
110 # No number means 1.0
113 # Unfortunately, this doesn't really work, since Standard isn't always default.
114 # But it's as good as we can do right now.
115 def find_default_layout(document, start, end):
116 l = find_token(document.body, "\\begin_layout Standard", start, end)
118 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
120 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
123 def get_option(document, m, option, default):
124 l = document.body[m].find(option)
127 val = document.body[m][l:].split('"')[1]
130 def remove_option(document, m, option):
131 l = document.body[m].find(option)
133 val = document.body[m][l:].split('"')[1]
134 document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
137 def set_option(document, m, option, value):
138 l = document.body[m].find(option)
140 oldval = document.body[m][l:].split('"')[1]
141 l = l + len(option + '="')
142 document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
144 document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
148 def read_unicodesymbols():
149 " Read the unicodesymbols list of unicode characters and corresponding commands."
150 pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
151 fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
153 # Two backslashes, followed by some non-word character, and then a character
154 # in brackets. The idea is to check for constructs like: \"{u}, which is how
155 # they are written in the unicodesymbols file; but they can also be written
156 # as: \"u or even \" u.
157 r = re.compile(r'\\\\(\W)\{(\w)\}')
158 for line in fp.readlines():
159 if line[0] != '#' and line.strip() != "":
160 line=line.replace(' "',' ') # remove all quotation marks with spaces before
161 line=line.replace('" ',' ') # remove all quotation marks with spaces after
162 line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
164 [ucs4,command,dead] = line.split(None,2)
165 if command[0:1] != "\\":
167 spec_chars.append([command, unichr(eval(ucs4))])
173 # If the character is a double-quote, then we need to escape it, too,
174 # since it is done that way in the LyX file.
175 if m.group(1) == "\"":
178 command += m.group(1) + m.group(2)
179 commandbl += m.group(1) + ' ' + m.group(2)
180 spec_chars.append([command, unichr(eval(ucs4))])
181 spec_chars.append([commandbl, unichr(eval(ucs4))])
186 def extract_argument(line):
187 'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
192 bracere = re.compile("(\s*)(.*)")
193 n = bracere.match(line)
194 whitespace = n.group(1)
197 if brace != "[" and brace != "{":
221 # We never found the matching brace
222 # So, to be on the safe side, let's just return everything
223 # which will then get wrapped as ERT
225 return (line[:pos + 1], line[pos + 1:])
228 def latex2ert(line, isindex):
229 '''Converts LaTeX commands into ERT. line may well be a multi-line
230 string when it is returned.'''
235 ## FIXME Escaped \ ??
236 # This regex looks for a LaTeX command---i.e., something of the form
237 # "\alPhaStuFF", or "\X", where X is any character---where the command
238 # may also be preceded by an additional backslash, which is how it would
239 # appear (e.g.) in an InsetIndex.
240 labelre = re.compile(r'(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)')
242 m = labelre.match(line)
249 (arg, rest) = extract_argument(end)
254 # If we wanted to put labels into an InsetLabel, for example, then we
255 # would just need to test here for cmd == "label" and then take some
256 # appropriate action, i.e., to use arg to get the content and then
257 # wrap it appropriately.
258 cmd = put_cmd_in_ert(cmd)
259 retval += "\n" + cmd + "\n"
261 m = labelre.match(line)
262 # put all remaining braces in ERT
263 line = wrap_into_ert(line, '}', '}')
264 line = wrap_into_ert(line, '{', '{')
266 # active character that is not available in all font encodings
267 line = wrap_into_ert(line, '|', '|')
272 unicode_reps = read_unicodesymbols()
275 #Might should do latex2ert first, then deal with stuff that DOESN'T
276 #end up inside ERT. That routine could be modified so that it returned
277 #a list of lines, and we could then skip ERT bits and only deal with
279 def latex2lyx(data, isindex):
280 '''Takes a string, possibly multi-line, and returns the result of
281 converting LaTeX constructs into LyX constructs. Returns a list of
282 lines, suitable for insertion into document.body.
283 The bool isindex specifies whether we are in an index macro (which
284 has some specific active characters that need to be ERTed).'''
290 # Convert LaTeX to Unicode
291 # Commands of this sort need to be checked to make sure they are
292 # followed by a non-alpha character, lest we replace too much.
293 hardone = re.compile(r'^\\\\[a-zA-Z]+$')
295 for rep in unicode_reps:
296 if hardone.match(rep[0]):
299 pos = data.find(rep[0], pos)
302 nextpos = pos + len(rep[0])
303 if nextpos < len(data) and data[nextpos].isalpha():
304 # not the end of that command
307 data = data[:pos] + rep[1] + data[nextpos:]
310 data = data.replace(rep[0], rep[1])
314 data = wrap_into_ert(data, r'\"', '"')
316 data = data.replace('\\\\', '\\')
319 mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
320 lines = data.split('\n')
322 #document.warning("LINE: " + line)
323 #document.warning(str(i) + ":" + document.body[i])
324 #document.warning("LAST: " + document.body[-1])
329 f = m.group(2).replace('\\\\', '\\')
333 s = latex2ert(s, isindex)
334 subst = s.split('\n')
336 retval.append("\\begin_inset Formula " + f)
337 retval.append("\\end_inset")
339 # Handle whatever is left, which is just text
340 g = latex2ert(g, isindex)
341 subst = g.split('\n')
346 def lyxline2latex(document, line, inert):
347 'Convert some LyX stuff into corresponding LaTeX stuff line-wise, as best we can.'
348 if line.startswith("\\begin_inset Formula"):
350 elif line.startswith("\\begin_inset Quotes"):
351 # For now, we do a very basic reversion. Someone who understands
352 # quotes is welcome to fix it up.
353 qtype = line[20:].strip()
367 elif line.isspace() or \
368 line.startswith("\\begin_layout") or \
369 line.startswith("\\end_layout") or \
370 line.startswith("\\begin_inset") or \
371 line.startswith("\\end_inset") or \
372 line.startswith("\\lang") or \
373 line.strip() == "status collapsed" or \
374 line.strip() == "status open":
378 # this needs to be added to the preamble because of cases like
379 # \textmu, \textbackslash, etc.
380 add_to_preamble(document, ['% added by lyx2lyx for converted entries',
381 '\\@ifundefined{textmu}',
382 ' {\\usepackage{textcomp}}{}'])
383 # a lossless reversion is not possible
384 # try at least to handle some common insets and settings
386 line = line.replace(r'\backslash', '\\')
388 line = line.replace('&', '\\&{}')
389 line = line.replace('#', '\\#{}')
390 line = line.replace('^', '\\^{}')
391 line = line.replace('%', '\\%{}')
392 line = line.replace('_', '\\_{}')
393 line = line.replace('$', '\\${}')
395 # Do the LyX text --> LaTeX conversion
396 for rep in unicode_reps:
397 line = line.replace(rep[1], rep[0].replace('\\\\', '\\') + "{}")
398 line = line.replace(r'\backslash', r'\textbackslash{}')
399 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
400 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
401 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
402 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
403 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
404 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
405 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
406 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
407 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
411 def lyx2latex(document, lines):
412 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
413 # clean up multiline stuff
417 for curline in range(len(lines)):
418 line = lines[curline]
419 if line.startswith("\\begin_inset ERT"):
420 # We don't want to replace things inside ERT, so figure out
421 # where the end of the inset is.
422 ert_end = find_end_of_inset(lines, curline + 1)
424 inert = ert_end >= curline
425 content += lyxline2latex(document, lines[curline], inert)
430 ####################################################################
432 def convert_ltcaption(document):
435 i = find_token(document.body, "\\begin_inset Tabular", i)
438 j = find_end_of_inset(document.body, i + 1)
440 document.warning("Malformed LyX document: Could not find end of tabular.")
443 nrows = int(document.body[i+1].split('"')[3])
444 ncols = int(document.body[i+1].split('"')[5])
447 for k in range(nrows):
448 m = find_token(document.body, "<row", m)
451 for k in range(ncols):
452 m = find_token(document.body, "<cell", m)
454 mend = find_token(document.body, "</cell>", m + 1)
455 # first look for caption insets
456 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
457 # then look for ERT captions
459 mcap = find_token(document.body, "caption", m + 1, mend)
461 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
464 if caption == 'true':
466 set_option(document, r, 'caption', 'true')
467 set_option(document, m, 'multicolumn', '1')
468 set_option(document, m, 'bottomline', 'false')
469 set_option(document, m, 'topline', 'false')
470 set_option(document, m, 'rightline', 'false')
471 set_option(document, m, 'leftline', 'false')
472 #j = find_end_of_inset(document.body, j + 1)
474 set_option(document, m, 'multicolumn', '2')
481 #FIXME Use of wrap_into_ert can confuse lyx2lyx
482 def revert_ltcaption(document):
485 i = find_token(document.body, "\\begin_inset Tabular", i)
488 j = find_end_of_inset(document.body, i + 1)
490 document.warning("Malformed LyX document: Could not find end of tabular.")
495 nrows = int(document.body[i+1].split('"')[3])
496 ncols = int(document.body[i+1].split('"')[5])
498 for k in range(nrows):
499 m = find_token(document.body, "<row", m)
500 caption = get_option(document, m, 'caption', 'false')
501 if caption == 'true':
502 remove_option(document, m, 'caption')
503 for k in range(ncols):
504 m = find_token(document.body, "<cell", m)
505 remove_option(document, m, 'multicolumn')
507 m = find_token(document.body, "\\begin_inset Caption", m)
510 m = find_end_of_inset(document.body, m + 1)
511 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
517 def convert_tablines(document):
520 i = find_token(document.body, "\\begin_inset Tabular", i)
522 # LyX 1.3 inserted an extra space between \begin_inset
523 # and Tabular so let us try if this is the case and fix it.
524 i = find_token(document.body, "\\begin_inset Tabular", i)
528 document.body[i] = "\\begin_inset Tabular"
529 j = find_end_of_inset(document.body, i + 1)
531 document.warning("Malformed LyX document: Could not find end of tabular.")
535 nrows = int(document.body[i+1].split('"')[3])
536 ncols = int(document.body[i+1].split('"')[5])
539 for k in range(ncols):
540 m = find_token(document.body, "<column", m)
541 left = get_option(document, m, 'leftline', 'false')
542 right = get_option(document, m, 'rightline', 'false')
543 col_info.append([left, right])
544 remove_option(document, m, 'leftline')
545 remove_option(document, m, 'rightline')
549 for k in range(nrows):
550 m = find_token(document.body, "<row", m)
551 top = get_option(document, m, 'topline', 'false')
552 bottom = get_option(document, m, 'bottomline', 'false')
553 row_info.append([top, bottom])
554 remove_option(document, m, 'topline')
555 remove_option(document, m, 'bottomline')
560 for k in range(nrows*ncols):
561 m = find_token(document.body, "<cell", m)
562 mc_info.append(get_option(document, m, 'multicolumn', '0'))
565 for l in range(nrows):
566 for k in range(ncols):
567 m = find_token(document.body, '<cell', m)
568 if mc_info[l*ncols + k] == '0':
569 r = set_option(document, m, 'topline', row_info[l][0])
570 r = set_option(document, m, 'bottomline', row_info[l][1])
571 r = set_option(document, m, 'leftline', col_info[k][0])
572 r = set_option(document, m, 'rightline', col_info[k][1])
573 elif mc_info[l*ncols + k] == '1':
575 while s < ncols and mc_info[l*ncols + s] == '2':
577 if s < ncols and mc_info[l*ncols + s] != '1':
578 r = set_option(document, m, 'rightline', col_info[k][1])
579 if k > 0 and mc_info[l*ncols + k - 1] == '0':
580 r = set_option(document, m, 'leftline', col_info[k][0])
585 def revert_tablines(document):
588 i = find_token(document.body, "\\begin_inset Tabular", i)
591 j = find_end_of_inset(document.body, i)
593 document.warning("Malformed LyX document: Could not find end of tabular.")
598 nrows = int(document.body[i+1].split('"')[3])
599 ncols = int(document.body[i+1].split('"')[5])
602 for k in range(nrows*ncols):
603 m = find_token(document.body, "<cell", m)
604 top = get_option(document, m, 'topline', 'false')
605 bottom = get_option(document, m, 'bottomline', 'false')
606 left = get_option(document, m, 'leftline', 'false')
607 right = get_option(document, m, 'rightline', 'false')
608 lines.append([top, bottom, left, right])
611 # we will want to ignore longtable captions
614 for k in range(nrows):
615 m = find_token(document.body, "<row", m)
616 caption = get_option(document, m, 'caption', 'false')
617 caption_info.append([caption])
622 for k in range(ncols):
623 m = find_token(document.body, "<column", m)
625 for l in range(nrows):
626 left = lines[l*ncols + k][2]
627 if left == 'false' and caption_info[l] == 'false':
629 set_option(document, m, 'leftline', left)
631 for l in range(nrows):
632 right = lines[l*ncols + k][3]
633 if right == 'false' and caption_info[l] == 'false':
635 set_option(document, m, 'rightline', right)
639 for k in range(nrows):
640 m = find_token(document.body, "<row", m)
642 for l in range(ncols):
643 top = lines[k*ncols + l][0]
646 if caption_info[k] == 'false':
648 set_option(document, m, 'topline', top)
650 for l in range(ncols):
651 bottom = lines[k*ncols + l][1]
652 if bottom == 'false':
654 if caption_info[k] == 'false':
656 set_option(document, m, 'bottomline', bottom)
662 def fix_wrong_tables(document):
665 i = find_token(document.body, "\\begin_inset Tabular", i)
668 j = find_end_of_inset(document.body, i + 1)
670 document.warning("Malformed LyX document: Could not find end of tabular.")
674 nrows = int(document.body[i+1].split('"')[3])
675 ncols = int(document.body[i+1].split('"')[5])
677 for l in range(nrows):
679 for k in range(ncols):
680 m = find_token(document.body, '<cell', m)
682 if document.body[m].find('multicolumn') != -1:
683 multicol_cont = int(document.body[m].split('"')[1])
685 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
686 document.body[m] = document.body[m][:5] + document.body[m][21:]
689 prev_multicolumn = multicol_cont
696 def close_begin_deeper(document):
700 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
705 if document.body[i][:13] == "\\begin_deeper":
712 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
715 def long_charstyle_names(document):
718 i = find_token(document.body, "\\begin_inset CharStyle", i)
721 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
724 def revert_long_charstyle_names(document):
727 i = find_token(document.body, "\\begin_inset CharStyle", i)
730 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
734 def axe_show_label(document):
737 i = find_token(document.body, "\\begin_inset CharStyle", i)
740 if document.body[i + 1].find("show_label") != -1:
741 if document.body[i + 1].find("true") != -1:
742 document.body[i + 1] = "status open"
743 del document.body[ i + 2]
745 if document.body[i + 1].find("false") != -1:
746 document.body[i + 1] = "status collapsed"
747 del document.body[ i + 2]
749 document.warning("Malformed LyX document: show_label neither false nor true.")
751 document.warning("Malformed LyX document: show_label missing in CharStyle.")
756 def revert_show_label(document):
759 i = find_token(document.body, "\\begin_inset CharStyle", i)
762 if document.body[i + 1].find("status open") != -1:
763 document.body.insert(i + 1, "show_label true")
765 if document.body[i + 1].find("status collapsed") != -1:
766 document.body.insert(i + 1, "show_label false")
768 document.warning("Malformed LyX document: no legal status line in CharStyle.")
771 def revert_begin_modules(document):
774 i = find_token(document.header, "\\begin_modules", i)
777 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
779 # this should not happen
781 document.header[i : j + 1] = []
783 def convert_flex(document):
784 "Convert CharStyle to Flex"
787 i = find_token(document.body, "\\begin_inset CharStyle", i)
790 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
792 def revert_flex(document):
793 "Convert Flex to CharStyle"
796 i = find_token(document.body, "\\begin_inset Flex", i)
799 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
802 def revert_pdf_options(document):
803 "Revert PDF options for hyperref."
804 # store the PDF options and delete the entries from the Lyx file
812 bookmarksnumbered = ""
814 bookmarksopenlevel = ""
822 i = find_token(document.header, "\\use_hyperref", i)
824 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
825 del document.header[i]
826 i = find_token(document.header, "\\pdf_store_options", i)
828 del document.header[i]
829 i = find_token(document.header, "\\pdf_title", 0)
831 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
832 title = ' pdftitle={' + title + '}'
833 del document.header[i]
834 i = find_token(document.header, "\\pdf_author", 0)
836 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
838 author = ' pdfauthor={' + author + '}'
840 author = ',\n pdfauthor={' + author + '}'
841 del document.header[i]
842 i = find_token(document.header, "\\pdf_subject", 0)
844 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
845 if title == "" and author == "":
846 subject = ' pdfsubject={' + subject + '}'
848 subject = ',\n pdfsubject={' + subject + '}'
849 del document.header[i]
850 i = find_token(document.header, "\\pdf_keywords", 0)
852 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
853 if title == "" and author == "" and subject == "":
854 keywords = ' pdfkeywords={' + keywords + '}'
856 keywords = ',\n pdfkeywords={' + keywords + '}'
857 del document.header[i]
858 i = find_token(document.header, "\\pdf_bookmarks", 0)
860 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
861 bookmarks = ',\n bookmarks=' + bookmarks
862 del document.header[i]
863 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
865 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
866 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
867 del document.header[i]
868 i = find_token(document.header, "\\pdf_bookmarksopen", i)
870 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
871 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
872 del document.header[i]
873 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
875 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
876 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
877 del document.header[i]
878 i = find_token(document.header, "\\pdf_breaklinks", i)
880 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
881 breaklinks = ',\n breaklinks=' + breaklinks
882 del document.header[i]
883 i = find_token(document.header, "\\pdf_pdfborder", i)
885 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
886 if pdfborder == 'true':
887 pdfborder = ',\n pdfborder={0 0 0}'
889 pdfborder = ',\n pdfborder={0 0 1}'
890 del document.header[i]
891 i = find_token(document.header, "\\pdf_colorlinks", i)
893 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
894 colorlinks = ',\n colorlinks=' + colorlinks
895 del document.header[i]
896 i = find_token(document.header, "\\pdf_backref", i)
898 backref = get_value_string(document.header, '\\pdf_backref', 0)
899 backref = ',\n backref=' + backref
900 del document.header[i]
901 i = find_token(document.header, "\\pdf_pagebackref", i)
903 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
904 pagebackref = ',\n pagebackref=' + pagebackref
905 del document.header[i]
906 i = find_token(document.header, "\\pdf_pagemode", 0)
908 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
909 pagemode = ',\n pdfpagemode=' + pagemode
910 del document.header[i]
911 i = find_token(document.header, "\\pdf_quoted_options", 0)
913 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
914 if title == "" and author == "" and subject == "" and keywords == "":
915 otheroptions = ' ' + otheroptions
917 otheroptions = ',\n ' + otheroptions
918 del document.header[i]
920 # write to the preamble when hyperref was used
922 # preamble write preparations
923 # bookmark numbers are only output when they are turned on
924 if bookmarksopen == ',\n bookmarksopen=true':
925 bookmarksopen = bookmarksopen + bookmarksopenlevel
926 if bookmarks == ',\n bookmarks=true':
927 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
929 bookmarks = bookmarks
930 # hypersetup is only output when there are things to be set up
931 setupstart = '\\hypersetup{%\n'
933 if otheroptions == "" and title == "" and author == ""\
934 and subject == "" and keywords == "":
938 # babel must be loaded before hyperref and hyperref the first part
939 # of the preamble, like in LyX 1.6
940 insert_to_preamble(0, document,
941 '% Commands inserted by lyx2lyx for PDF properties\n'
942 + '\\usepackage{babel}\n'
943 + '\\usepackage[unicode=true'
962 def remove_inzip_options(document):
963 "Remove inzipName and embed options from the Graphics inset"
966 i = find_token(document.body, "\\begin_inset Graphics", i)
969 j = find_end_of_inset(document.body, i + 1)
972 document.warning("Malformed LyX document: Could not find end of graphics inset.")
973 # If there's a inzip param, just remove that
974 k = find_token(document.body, "\tinzipName", i + 1, j)
977 # embed option must follow the inzipName option
978 del document.body[k+1]
982 def convert_inset_command(document):
985 \begin_inset LatexCommand cmd
987 \begin_inset CommandInset InsetType
992 i = find_token(document.body, "\\begin_inset LatexCommand", i)
995 line = document.body[i]
996 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
1000 #this is adapted from factory.cpp
1001 if cmdName[0:4].lower() == "cite":
1002 insetName = "citation"
1003 elif cmdName == "url" or cmdName == "htmlurl":
1005 elif cmdName[-3:] == "ref":
1007 elif cmdName == "tableofcontents":
1009 elif cmdName == "printnomenclature":
1010 insetName = "nomencl_print"
1011 elif cmdName == "printindex":
1012 insetName = "index_print"
1015 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
1016 document.body[i : i+1] = insertion
1019 def revert_inset_command(document):
1022 \begin_inset CommandInset InsetType
1025 \begin_inset LatexCommand cmd
1026 Some insets may end up being converted to insets earlier versions of LyX
1027 will not be able to recognize. Not sure what to do about that.
1031 i = find_token(document.body, "\\begin_inset CommandInset", i)
1034 nextline = document.body[i+1]
1035 r = re.compile(r'LatexCommand\s+(.*)$')
1036 m = r.match(nextline)
1038 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
1041 cmdName = m.group(1)
1042 insertion = ["\\begin_inset LatexCommand " + cmdName]
1043 document.body[i : i+2] = insertion
1046 def convert_wrapfig_options(document):
1047 "Convert optional options for wrap floats (wrapfig)."
1048 # adds the tokens "lines", "placement", and "overhang"
1051 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1054 document.body.insert(i + 1, "lines 0")
1055 j = find_token(document.body, "placement", i)
1056 # placement can be already set or not; if not, set it
1058 document.body.insert(i + 3, "overhang 0col%")
1060 document.body.insert(i + 2, "placement o")
1061 document.body.insert(i + 3, "overhang 0col%")
1065 def revert_wrapfig_options(document):
1066 "Revert optional options for wrap floats (wrapfig)."
1069 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1072 j = find_end_of_inset(document.body, i)
1074 document.warning("Can't find end of Wrap inset at line " + str(i))
1077 k = find_default_layout(document, i, j)
1079 document.warning("Can't find default layout for Wrap figure!")
1082 # Options should be between i and k now
1083 l = find_token(document.body, "lines", i, k)
1085 document.warning("Can't find lines option for Wrap figure!")
1088 m = find_token(document.body, "overhang", i + 1, k)
1090 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1093 # Do these in reverse order
1094 del document.body[m]
1095 del document.body[l]
1099 def convert_latexcommand_index(document):
1100 "Convert from LatexCommand form to collapsable form."
1102 r1 = re.compile('name "(.*)"')
1104 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1107 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1110 j = find_end_of_inset(document.body, i + 1)
1112 document.warning("Unable to find end of index inset at line " + str(i) + "!")
1115 m = r1.match(document.body[i + 2])
1117 document.warning("Unable to match: " + document.body[i+2])
1118 # this can happen with empty index insets!
1121 fullcontent = m.group(1)
1122 linelist = latex2lyx(fullcontent, True)
1123 #document.warning(fullcontent)
1125 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1126 linelist + ["\\end_layout"]
1127 document.body[i : j] = linelist
1128 i += len(linelist) - (j - i)
1131 def revert_latexcommand_index(document):
1132 "Revert from collapsable form to LatexCommand form."
1135 i = find_token(document.body, "\\begin_inset Index", i)
1138 j = find_end_of_inset(document.body, i + 1)
1142 content = lyx2latex(document, document.body[i:j])
1144 content = content.replace('"', r'\"')
1145 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1146 "name " + '"' + content + '"', ""]
1150 def revert_wraptable(document):
1151 "Revert wrap table to wrap figure."
1154 i = find_token(document.body, "\\begin_inset Wrap table", i)
1157 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1161 def revert_vietnamese(document):
1162 "Set language Vietnamese to English"
1163 # Set document language from Vietnamese to English
1165 if document.language == "vietnamese":
1166 document.language = "english"
1167 i = find_token(document.header, "\\language", 0)
1169 document.header[i] = "\\language english"
1172 j = find_token(document.body, "\\lang vietnamese", j)
1175 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1179 def convert_japanese_cjk(document):
1180 "Set language japanese to japanese-cjk"
1181 # Set document language from japanese-plain to japanese
1183 if document.language == "japanese":
1184 document.language = "japanese-cjk"
1185 i = find_token(document.header, "\\language", 0)
1187 document.header[i] = "\\language japanese-cjk"
1190 j = find_token(document.body, "\\lang japanese", j)
1193 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1197 def revert_japanese(document):
1198 "Set language japanese-plain to japanese"
1199 # Set document language from japanese-plain to japanese
1201 if document.language == "japanese-plain":
1202 document.language = "japanese"
1203 i = find_token(document.header, "\\language", 0)
1205 document.header[i] = "\\language japanese"
1208 j = find_token(document.body, "\\lang japanese-plain", j)
1211 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1215 def revert_japanese_cjk(document):
1216 "Set language japanese-cjk to japanese"
1217 # Set document language from japanese-plain to japanese
1219 if document.language == "japanese-cjk":
1220 document.language = "japanese"
1221 i = find_token(document.header, "\\language", 0)
1223 document.header[i] = "\\language japanese"
1226 j = find_token(document.body, "\\lang japanese-cjk", j)
1229 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1233 def revert_japanese_encoding(document):
1234 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1235 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1237 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1239 document.header[i] = "\\inputencoding EUC-JP"
1241 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1243 document.header[j] = "\\inputencoding JIS"
1245 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1246 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1247 document.header[k] = "\\inputencoding UTF8"
1250 def revert_inset_info(document):
1251 'Replace info inset with its content'
1254 i = find_token(document.body, '\\begin_inset Info', i)
1257 j = find_end_of_inset(document.body, i + 1)
1260 document.warning("Malformed LyX document: Could not find end of Info inset.")
1263 for k in range(i, j+1):
1264 if document.body[k].startswith("arg"):
1265 arg = document.body[k][3:].strip()
1266 # remove embracing quotation marks
1269 if arg[len(arg) - 1] == '"':
1270 arg = arg[:len(arg) - 1]
1271 # \" to straight quote
1272 arg = arg.replace(r'\"', '"')
1274 arg = arg.replace(r'\\', "\\backslash\n")
1275 if document.body[k].startswith("type"):
1276 type = document.body[k][4:].strip().strip('"')
1277 # I think there is a newline after \\end_inset, which should be removed.
1278 if document.body[j + 1].strip() == "":
1279 document.body[i : (j + 2)] = [type + ':' + arg]
1281 document.body[i : (j + 1)] = [type + ':' + arg]
1284 def convert_pdf_options(document):
1285 # Set the pdfusetitle tag, delete the pdf_store_options,
1286 # set quotes for bookmarksopenlevel"
1287 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1289 k = find_token(document.header, "\\use_hyperref", 0)
1290 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1291 k = find_token(document.header, "\\pdf_store_options", 0)
1293 del document.header[k]
1294 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1296 document.header[i] = document.header[i].replace('"', '')
1299 def revert_pdf_options_2(document):
1300 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1301 k = find_token(document.header, "\\use_hyperref", 0)
1302 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1304 del document.header[i]
1305 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1307 values = document.header[i].split()
1308 values[1] = ' "' + values[1] + '"'
1309 document.header[i] = ''.join(values)
1312 def convert_htmlurl(document):
1313 'Convert "htmlurl" to "href" insets for docbook'
1314 if document.backend != "docbook":
1318 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1321 document.body[i] = "\\begin_inset CommandInset href"
1322 document.body[i + 1] = "LatexCommand href"
1326 def convert_url(document):
1327 'Convert url insets to url charstyles'
1328 if document.backend == "docbook":
1332 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1335 n = find_token(document.body, "name", i)
1337 # place the URL name in typewriter before the new URL insert
1338 # grab the name 'bla' from the e.g. the line 'name "bla"',
1339 # therefore start with the 6th character
1340 name = document.body[n][6:-1]
1341 newname = [name + " "]
1342 document.body[i:i] = newname
1344 j = find_token(document.body, "target", i)
1346 document.warning("Malformed LyX document: Can't find target for url inset")
1349 target = document.body[j][8:-1]
1350 k = find_token(document.body, "\\end_inset", j)
1352 document.warning("Malformed LyX document: Can't find end of url inset")
1355 newstuff = ["\\begin_inset Flex URL",
1356 "status collapsed", "",
1357 "\\begin_layout Standard",
1362 document.body[i:k] = newstuff
1363 i = i + len(newstuff)
1365 def convert_ams_classes(document):
1366 tc = document.textclass
1367 if (tc != "amsart" and tc != "amsart-plain" and
1368 tc != "amsart-seq" and tc != "amsbook"):
1370 if tc == "amsart-plain":
1371 document.textclass = "amsart"
1372 document.set_textclass()
1373 document.add_module("Theorems (Starred)")
1375 if tc == "amsart-seq":
1376 document.textclass = "amsart"
1377 document.set_textclass()
1378 document.add_module("Theorems (AMS)")
1380 #Now we want to see if any of the environments in the extended theorems
1381 #module were used in this document. If so, we'll add that module, too.
1382 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1383 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1386 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1389 i = find_token(document.body, "\\begin_layout", i)
1392 m = r.match(document.body[i])
1394 # This is an empty layout
1395 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1399 if layouts.count(m) != 0:
1400 document.add_module("Theorems (AMS-Extended)")
1404 def revert_href(document):
1405 'Reverts hyperlink insets (href) to url insets (url)'
1408 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1411 document.body[i : i + 2] = \
1412 ["\\begin_inset CommandInset url", "LatexCommand url"]
1415 def revert_url(document):
1416 'Reverts Flex URL insets to old-style URL insets'
1419 i = find_token(document.body, "\\begin_inset Flex URL", i)
1422 j = find_end_of_inset(document.body, i)
1424 document.warning("Can't find end of inset in revert_url!")
1426 k = find_default_layout(document, i, j)
1428 document.warning("Can't find default layout in revert_url!")
1431 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1432 if l == -1 or l >= j:
1433 document.warning("Can't find end of default layout in revert_url!")
1436 # OK, so the inset's data is between lines k and l.
1437 data = " ".join(document.body[k+1:l])
1439 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1441 document.body[i:j+1] = newinset
1442 i = i + len(newinset)
1445 def convert_include(document):
1446 'Converts include insets to new format.'
1448 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1450 i = find_token(document.body, "\\begin_inset Include", i)
1453 line = document.body[i]
1454 previewline = document.body[i + 1]
1457 document.warning("Unable to match line " + str(i) + " of body!")
1463 insertion = ["\\begin_inset CommandInset include",
1464 "LatexCommand " + cmd, previewline,
1465 "filename \"" + fn + "\""]
1468 insertion.append("lstparams " + '"' + opt + '"')
1470 document.body[i : i + 2] = insertion
1474 def revert_include(document):
1475 'Reverts include insets to old format.'
1477 r0 = re.compile('preview.*')
1478 r1 = re.compile('LatexCommand (.+)')
1479 r2 = re.compile('filename "(.+)"')
1480 r3 = re.compile('lstparams "(.*)"')
1482 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1486 m = r1.match(document.body[nextline])
1488 document.warning("Malformed LyX document: No LatexCommand line for `" +
1489 document.body[i] + "' on line " + str(i) + ".")
1494 if r0.match(document.body[nextline]):
1495 previewline = document.body[nextline]
1499 m = r2.match(document.body[nextline])
1501 document.warning("Malformed LyX document: No filename line for `" + \
1502 document.body[i] + "' on line " + str(i) + ".")
1508 if (cmd == "lstinputlisting"):
1509 m = r3.match(document.body[nextline])
1511 options = m.group(1)
1514 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1516 newline += ("[" + options + "]")
1517 insertion = [newline]
1518 if previewline != "":
1519 insertion.append(previewline)
1520 document.body[i : nextline] = insertion
1524 def revert_albanian(document):
1525 "Set language Albanian to English"
1527 if document.language == "albanian":
1528 document.language = "english"
1529 i = find_token(document.header, "\\language", 0)
1531 document.header[i] = "\\language english"
1534 j = find_token(document.body, "\\lang albanian", j)
1537 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1541 def revert_lowersorbian(document):
1542 "Set language lower Sorbian to English"
1544 if document.language == "lowersorbian":
1545 document.language = "english"
1546 i = find_token(document.header, "\\language", 0)
1548 document.header[i] = "\\language english"
1551 j = find_token(document.body, "\\lang lowersorbian", j)
1554 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1558 def revert_uppersorbian(document):
1559 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1561 if document.language == "uppersorbian":
1562 document.language = "usorbian"
1563 i = find_token(document.header, "\\language", 0)
1565 document.header[i] = "\\language usorbian"
1568 j = find_token(document.body, "\\lang uppersorbian", j)
1571 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1575 def convert_usorbian(document):
1576 "Set language usorbian to uppersorbian"
1578 if document.language == "usorbian":
1579 document.language = "uppersorbian"
1580 i = find_token(document.header, "\\language", 0)
1582 document.header[i] = "\\language uppersorbian"
1585 j = find_token(document.body, "\\lang usorbian", j)
1588 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1592 def convert_macro_global(document):
1593 "Remove TeX code command \global when it is in front of a macro"
1594 # math macros are nowadays already defined \global, so that an additional
1595 # \global would make the document uncompilable, see
1596 # http://bugzilla.lyx.org/show_bug.cgi?id=5371
1597 # We're looking for something like this:
1601 # \begin_layout Plain Layout
1611 # \begin_inset FormulaMacro
1612 # \renewcommand{\foo}{123}
1616 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1619 # if i <= 13, then there isn't enough room for the ERT
1623 if document.body[i-6] == "global":
1624 del document.body[i-13 : i]
1630 def revert_macro_optional_params(document):
1631 "Convert macro definitions with optional parameters into ERTs"
1632 # Stub to convert macro definitions with one or more optional parameters
1633 # into uninterpreted ERT insets
1636 def revert_hyperlinktype(document):
1637 'Reverts hyperlink type'
1641 i = find_token(document.body, "target", i)
1644 j = find_token(document.body, "type", i)
1648 del document.body[j]
1652 def revert_pagebreak(document):
1653 'Reverts pagebreak to ERT'
1656 i = find_token(document.body, "\\pagebreak", i)
1659 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1660 '\\begin_layout Standard\n\n\n\\backslash\n' \
1661 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1665 def revert_linebreak(document):
1666 'Reverts linebreak to ERT'
1669 i = find_token(document.body, "\\linebreak", i)
1672 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1673 '\\begin_layout Standard\n\n\n\\backslash\n' \
1674 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1678 def revert_latin(document):
1679 "Set language Latin to English"
1681 if document.language == "latin":
1682 document.language = "english"
1683 i = find_token(document.header, "\\language", 0)
1685 document.header[i] = "\\language english"
1688 j = find_token(document.body, "\\lang latin", j)
1691 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1695 def revert_samin(document):
1696 "Set language North Sami to English"
1698 if document.language == "samin":
1699 document.language = "english"
1700 i = find_token(document.header, "\\language", 0)
1702 document.header[i] = "\\language english"
1705 j = find_token(document.body, "\\lang samin", j)
1708 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1712 def convert_serbocroatian(document):
1713 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1715 if document.language == "serbocroatian":
1716 document.language = "croatian"
1717 i = find_token(document.header, "\\language", 0)
1719 document.header[i] = "\\language croatian"
1722 j = find_token(document.body, "\\lang serbocroatian", j)
1725 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1729 def convert_framed_notes(document):
1730 "Convert framed notes to boxes. "
1733 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1736 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1745 'height_special "totalheight"']
1746 document.body[i:i+1] = subst
1750 def convert_module_names(document):
1751 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1752 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1753 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1754 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1755 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1756 modlist = document.get_module_list()
1757 if len(modlist) == 0:
1761 if modulemap.has_key(mod):
1762 newmodlist.append(modulemap[mod])
1764 document.warning("Can't find module %s in the module map!" % mod)
1765 newmodlist.append(mod)
1766 document.set_module_list(newmodlist)
1769 def revert_module_names(document):
1770 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1771 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1772 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1773 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1774 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1775 modlist = document.get_module_list()
1776 if len(modlist) == 0:
1780 if mod in modulemap:
1781 newmodlist.append(modulemap[mod])
1783 document.warning("Can't find module %s in the module map!" % mod)
1784 newmodlist.append(mod)
1785 document.set_module_list(newmodlist)
1788 def revert_colsep(document):
1789 i = find_token(document.header, "\\columnsep", 0)
1792 colsepline = document.header[i]
1793 r = re.compile(r'\\columnsep (.*)')
1794 m = r.match(colsepline)
1796 document.warning("Malformed column separation line!")
1799 del document.header[i]
1800 #it seems to be safe to add the package even if it is already used
1801 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1803 add_to_preamble(document, pretext)
1806 def revert_framed_notes(document):
1807 "Revert framed boxes to notes. "
1810 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1814 j = find_end_of_inset(document.body, i + 1)
1817 document.warning("Malformed LyX document: Could not find end of Box inset.")
1818 k = find_token(document.body, "status", i + 1, j)
1820 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1822 status = document.body[k]
1823 l = find_default_layout(document, i + 1, j)
1825 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1827 m = find_token(document.body, "\\end_layout", i + 1, j)
1829 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1831 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1832 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1833 if ibox == -1 and pbox == -1:
1834 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1835 del document.body[i+1:k]
1837 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1838 subst1 = [document.body[l],
1839 "\\begin_inset Note Shaded",
1841 '\\begin_layout Standard']
1842 document.body[l:l + 1] = subst1
1843 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1844 document.body[m:m + 1] = subst2
1848 def revert_slash(document):
1849 'Revert \\SpecialChar \\slash{} to ERT'
1851 while i < len(document.body):
1852 m = re.match(r'(.*)\\SpecialChar \\slash{}(.*)', document.body[i])
1857 '\\begin_inset ERT',
1858 'status collapsed', '',
1859 '\\begin_layout Standard',
1860 '', '', '\\backslash',
1865 document.body[i: i+1] = subst
1871 def revert_nobreakdash(document):
1872 'Revert \\SpecialChar \\nobreakdash- to ERT'
1874 while i < len(document.body):
1875 m = re.match(r'(.*)\\SpecialChar \\nobreakdash-(.*)', document.body[i])
1880 '\\begin_inset ERT',
1881 'status collapsed', '',
1882 '\\begin_layout Standard', '', '',
1888 document.body[i: i+1] = subst
1890 j = find_token(document.header, "\\use_amsmath", 0)
1892 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1894 document.header[j] = "\\use_amsmath 2"
1899 #Returns number of lines added/removed
1900 def revert_nocite_key(body, start, end):
1901 'key "..." -> \nocite{...}'
1902 r = re.compile(r'^key "(.*)"')
1906 m = r.match(body[i])
1908 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1909 j += 1 # because we added a line
1910 i += 2 # skip that line
1913 j -= 1 # because we deleted a line
1914 # no need to change i, since it now points to the next line
1918 def revert_nocite(document):
1919 "Revert LatexCommand nocite to ERT"
1922 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1925 if (document.body[i+1] != "LatexCommand nocite"):
1926 # note that we already incremented i
1929 insetEnd = find_end_of_inset(document.body, i)
1931 #this should not happen
1932 document.warning("End of CommandInset citation not found in revert_nocite!")
1935 paramLocation = i + 2 #start of the inset's parameters
1937 document.body[i:i+2] = \
1938 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1939 # that added two lines
1942 #print insetEnd, document.body[i: insetEnd + 1]
1943 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1944 #print insetEnd, document.body[i: insetEnd + 1]
1945 document.body.insert(insetEnd, "\\end_layout")
1946 document.body.insert(insetEnd + 1, "")
1950 def revert_btprintall(document):
1951 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1952 i = find_token(document.header, '\\use_bibtopic', 0)
1954 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1956 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1958 while i < len(document.body):
1959 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1962 j = find_end_of_inset(document.body, i + 1)
1964 #this should not happen
1965 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1966 j = len(document.body)
1967 # this range isn't really right, but it should be OK, since we shouldn't
1968 # see more than one matching line in each inset
1970 for k in range(i, j):
1971 if (document.body[k] == 'btprint "btPrintAll"'):
1972 del document.body[k]
1973 subst = ["\\begin_inset ERT",
1974 "status collapsed", "",
1975 "\\begin_layout Standard", "",
1980 document.body[i:i] = subst
1981 addlines = addedlines + len(subst) - 1
1985 def revert_bahasam(document):
1986 "Set language Bahasa Malaysia to Bahasa Indonesia"
1988 if document.language == "bahasam":
1989 document.language = "bahasa"
1990 i = find_token(document.header, "\\language", 0)
1992 document.header[i] = "\\language bahasa"
1995 j = find_token(document.body, "\\lang bahasam", j)
1998 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
2002 def revert_interlingua(document):
2003 "Set language Interlingua to English"
2005 if document.language == "interlingua":
2006 document.language = "english"
2007 i = find_token(document.header, "\\language", 0)
2009 document.header[i] = "\\language english"
2012 j = find_token(document.body, "\\lang interlingua", j)
2015 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
2019 def revert_serbianlatin(document):
2020 "Set language Serbian-Latin to Croatian"
2022 if document.language == "serbian-latin":
2023 document.language = "croatian"
2024 i = find_token(document.header, "\\language", 0)
2026 document.header[i] = "\\language croatian"
2029 j = find_token(document.body, "\\lang serbian-latin", j)
2032 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
2036 def revert_rotfloat(document):
2037 " Revert sideways custom floats. "
2040 # whitespace intended (exclude \\begin_inset FloatList)
2041 i = find_token(document.body, "\\begin_inset Float ", i)
2044 line = document.body[i]
2045 r = re.compile(r'\\begin_inset Float (.*)$')
2048 document.warning("Unable to match line " + str(i) + " of body!")
2051 floattype = m.group(1)
2052 if floattype == "figure" or floattype == "table":
2055 j = find_end_of_inset(document.body, i)
2057 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
2061 if get_value(document.body, 'sideways', i, j) == "false":
2064 l = find_default_layout(document, i + 1, j)
2066 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2068 subst = ['\\begin_layout Standard',
2069 '\\begin_inset ERT',
2070 'status collapsed', '',
2071 '\\begin_layout Standard', '', '',
2073 'end{sideways' + floattype + '}',
2074 '\\end_layout', '', '\\end_inset']
2075 document.body[j : j+1] = subst
2076 addedLines = len(subst) - 1
2077 del document.body[i+1 : l]
2078 addedLines -= (l-1) - (i+1)
2079 subst = ['\\begin_inset ERT', 'status collapsed', '',
2080 '\\begin_layout Standard', '', '', '\\backslash',
2081 'begin{sideways' + floattype + '}',
2082 '\\end_layout', '', '\\end_inset', '',
2084 document.body[i : i+1] = subst
2085 addedLines += len(subst) - 1
2086 if floattype == "algorithm":
2087 add_to_preamble(document,
2088 ['% Commands inserted by lyx2lyx for sideways algorithm float',
2089 '\\usepackage{rotfloat}',
2090 '\\floatstyle{ruled}',
2091 '\\newfloat{algorithm}{tbp}{loa}',
2092 '\\floatname{algorithm}{Algorithm}'])
2094 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
2098 def revert_widesideways(document):
2099 " Revert wide sideways floats. "
2102 # whitespace intended (exclude \\begin_inset FloatList)
2103 i = find_token(document.body, '\\begin_inset Float ', i)
2106 line = document.body[i]
2107 r = re.compile(r'\\begin_inset Float (.*)$')
2110 document.warning("Unable to match line " + str(i) + " of body!")
2113 floattype = m.group(1)
2114 if floattype != "figure" and floattype != "table":
2117 j = find_end_of_inset(document.body, i)
2119 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2122 if get_value(document.body, 'sideways', i, j) == "false" or \
2123 get_value(document.body, 'wide', i, j) == "false":
2126 l = find_default_layout(document, i + 1, j)
2128 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2130 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2131 'status collapsed', '',
2132 '\\begin_layout Standard', '', '', '\\backslash',
2133 'end{sideways' + floattype + '*}',
2134 '\\end_layout', '', '\\end_inset']
2135 document.body[j : j+1] = subst
2136 addedLines = len(subst) - 1
2137 del document.body[i+1:l-1]
2138 addedLines -= (l-1) - (i+1)
2139 subst = ['\\begin_inset ERT', 'status collapsed', '',
2140 '\\begin_layout Standard', '', '', '\\backslash',
2141 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2142 '\\end_inset', '', '\\end_layout', '']
2143 document.body[i : i+1] = subst
2144 addedLines += len(subst) - 1
2145 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2149 def revert_inset_embedding(document, type):
2150 ' Remove embed tag from certain type of insets'
2153 i = find_token(document.body, "\\begin_inset %s" % type, i)
2156 j = find_end_of_inset(document.body, i)
2158 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2161 k = find_token(document.body, "\tembed", i, j)
2163 k = find_token(document.body, "embed", i, j)
2165 del document.body[k]
2169 def revert_external_embedding(document):
2170 ' Remove embed tag from external inset '
2171 revert_inset_embedding(document, 'External')
2174 def convert_subfig(document):
2175 " Convert subfigures to subfloats. "
2179 i = find_token(document.body, '\\begin_inset Graphics', i)
2182 endInset = find_end_of_inset(document.body, i)
2184 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2187 k = find_token(document.body, '\tsubcaption', i, endInset)
2191 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2195 caption = document.body[l][16:].strip('"')
2196 del document.body[l]
2198 del document.body[k]
2200 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2201 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2202 '', '\\begin_layout Plain Layout'] + latex2lyx(caption, False) + \
2203 [ '\\end_layout', '', '\\end_inset', '',
2204 '\\end_layout', '', '\\begin_layout Plain Layout']
2205 document.body[i : i] = subst
2206 addedLines += len(subst)
2207 endInset += addedLines
2208 subst = ['', '\\end_inset', '', '\\end_layout']
2209 document.body[endInset : endInset] = subst
2210 addedLines += len(subst)
2214 def revert_subfig(document):
2215 " Revert subfloats. "
2218 # whitespace intended (exclude \\begin_inset FloatList)
2219 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2225 j = find_end_of_inset(document.body, i)
2227 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2228 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2230 continue # this will get us back to the outer loop, since j == -1
2231 # look for embedded float (= subfloat)
2232 # whitespace intended (exclude \\begin_inset FloatList)
2233 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2236 # is the subfloat aligned?
2237 al = find_token(document.body, '\\align ', k - 1, j)
2241 if get_value(document.body, '\\align', al) == "center":
2242 alignment_beg = "\\backslash\nbegin{centering}"
2243 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2244 elif get_value(document.body, '\\align', al) == "left":
2245 alignment_beg = "\\backslash\nbegin{raggedright}"
2246 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2247 elif get_value(document.body, '\\align', al) == "right":
2248 alignment_beg = "\\backslash\nbegin{raggedleft}"
2249 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2250 l = find_end_of_inset(document.body, k)
2252 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2255 continue # escape to the outer loop
2256 m = find_default_layout(document, k + 1, l)
2258 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2263 capend = find_end_of_inset(document.body, cap)
2265 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2269 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2271 lblend = find_end_of_inset(document.body, lbl + 1)
2273 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2275 for line in document.body[lbl:lblend + 1]:
2276 if line.startswith('name '):
2277 label = line.split()[1].strip('"')
2284 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2286 optend = find_end_of_inset(document.body, opt)
2288 document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
2290 optc = find_default_layout(document, opt, optend)
2292 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2294 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2295 for line in document.body[optc:optcend]:
2296 if not line.startswith('\\'):
2297 shortcap += line.strip()
2301 for line in document.body[cap:capend]:
2302 if line in document.body[lbl:lblend]:
2304 elif line in document.body[opt:optend]:
2308 caption += lyxline2latex(document, line, inert)
2310 caption += "\n\\backslash\nlabel{" + label + "}"
2311 subst = '\\begin_layout PlainLayout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2312 '\\begin_layout PlainLayout\n\n}' + alignment_end + \
2313 '\n\\end_layout\n\n\\end_inset\n\n' \
2314 '\\end_layout\n\n\\begin_layout PlainLayout\n'
2315 subst = subst.split('\n')
2316 document.body[l : l+1] = subst
2317 addedLines = len(subst) - 1
2318 # this is before l and so is unchanged by the multiline insertion
2320 del document.body[cap:capend+1]
2321 addedLines -= (capend + 1 - cap)
2322 del document.body[k+1:m-1]
2323 addedLines -= (m - 1 - (k + 1))
2324 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2325 '\\begin_layout PlainLayout\n\n' + alignment_beg + '\n\\backslash\n' \
2327 if len(shortcap) > 0:
2328 insertion = insertion + "[" + shortcap + "]"
2329 if len(caption) > 0:
2330 insertion = insertion + "[" + caption + "]"
2331 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2332 insertion = insertion.split('\n')
2333 document.body[k : k + 1] = insertion
2334 addedLines += len(insertion) - 1
2335 al = find_token(document.body, '\\align ', k - 1, j + addedLines)
2337 del document.body[al]
2339 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2343 def revert_wrapplacement(document):
2344 " Revert placement options wrap floats (wrapfig). "
2347 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2350 e = find_end_of_inset(document.body, i)
2351 j = find_token(document.body, "placement", i + 1, e)
2353 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2356 r = re.compile("placement (o|i|l|r|O|I|L|R)")
2357 m = r.match(document.body[j])
2359 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2361 document.body[j] = "placement " + m.group(1).lower()
2365 def remove_extra_embedded_files(document):
2366 " Remove \extra_embedded_files from buffer params "
2367 i = find_token(document.header, '\\extra_embedded_files', 0)
2370 document.header.pop(i)
2373 def convert_spaceinset(document):
2374 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2376 while i < len(document.body):
2377 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2381 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2382 document.body[i: i+1] = subst
2388 def revert_spaceinset(document):
2389 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2392 i = find_token(document.body, "\\begin_inset Space", i)
2395 j = find_end_of_inset(document.body, i)
2397 document.warning("Malformed LyX document: Could not find end of space inset.")
2399 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2400 del document.body[j]
2403 def convert_hfill(document):
2404 " Convert hfill to space inset "
2407 i = find_token(document.body, "\\hfill", i)
2410 subst = document.body[i].replace('\\hfill', \
2411 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2412 subst = subst.split('\n')
2413 document.body[i : i+1] = subst
2417 def revert_hfills(document):
2418 ' Revert \\hfill commands '
2419 hfill = re.compile(r'\\hfill')
2420 dotfill = re.compile(r'\\dotfill')
2421 hrulefill = re.compile(r'\\hrulefill')
2424 i = find_token(document.body, "\\InsetSpace", i)
2427 if hfill.search(document.body[i]):
2428 document.body[i] = \
2429 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2432 if dotfill.search(document.body[i]):
2433 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2434 '\\begin_inset ERT\nstatus collapsed\n\n' \
2435 '\\begin_layout Standard\n\n\n\\backslash\n' \
2436 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2437 subst = subst.split('\n')
2438 document.body[i : i+1] = subst
2441 if hrulefill.search(document.body[i]):
2442 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2443 '\\begin_inset ERT\nstatus collapsed\n\n' \
2444 '\\begin_layout Standard\n\n\n\\backslash\n' \
2445 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2446 subst = subst.split('\n')
2447 document.body[i : i+1] = subst
2452 def revert_hspace(document):
2453 ' Revert \\InsetSpace \\hspace{} to ERT '
2455 hspace = re.compile(r'\\hspace{}')
2456 hstar = re.compile(r'\\hspace\*{}')
2458 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2461 length = get_value(document.body, '\\length', i+1)
2463 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2465 del document.body[i+1]
2467 if hstar.search(document.body[i]):
2468 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2469 '\\begin_inset ERT\nstatus collapsed\n\n' \
2470 '\\begin_layout Standard\n\n\n\\backslash\n' \
2471 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2472 subst = subst.split('\n')
2473 document.body[i : i+1] = subst
2474 addedLines += len(subst) - 1
2477 if hspace.search(document.body[i]):
2478 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2479 '\\begin_inset ERT\nstatus collapsed\n\n' \
2480 '\\begin_layout Standard\n\n\n\\backslash\n' \
2481 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2482 subst = subst.split('\n')
2483 document.body[i : i+1] = subst
2484 addedLines += len(subst) - 1
2490 def revert_protected_hfill(document):
2491 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2494 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2497 j = find_end_of_inset(document.body, i)
2499 document.warning("Malformed LyX document: Could not find end of space inset.")
2501 del document.body[j]
2502 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2503 '\\begin_inset ERT\nstatus collapsed\n\n' \
2504 '\\begin_layout Standard\n\n\n\\backslash\n' \
2505 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2506 subst = subst.split('\n')
2507 document.body[i : i+1] = subst
2511 def revert_leftarrowfill(document):
2512 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2515 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2518 j = find_end_of_inset(document.body, i)
2520 document.warning("Malformed LyX document: Could not find end of space inset.")
2522 del document.body[j]
2523 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2524 '\\begin_inset ERT\nstatus collapsed\n\n' \
2525 '\\begin_layout Standard\n\n\n\\backslash\n' \
2526 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2527 subst = subst.split('\n')
2528 document.body[i : i+1] = subst
2532 def revert_rightarrowfill(document):
2533 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2536 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2539 j = find_end_of_inset(document.body, i)
2541 document.warning("Malformed LyX document: Could not find end of space inset.")
2543 del document.body[j]
2544 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2545 '\\begin_inset ERT\nstatus collapsed\n\n' \
2546 '\\begin_layout Standard\n\n\n\\backslash\n' \
2547 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2548 subst = subst.split('\n')
2549 document.body[i : i+1] = subst
2553 def revert_upbracefill(document):
2554 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2557 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2560 j = find_end_of_inset(document.body, i)
2562 document.warning("Malformed LyX document: Could not find end of space inset.")
2564 del document.body[j]
2565 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2566 '\\begin_inset ERT\nstatus collapsed\n\n' \
2567 '\\begin_layout Standard\n\n\n\\backslash\n' \
2568 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2569 subst = subst.split('\n')
2570 document.body[i : i+1] = subst
2574 def revert_downbracefill(document):
2575 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2578 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2581 j = find_end_of_inset(document.body, i)
2583 document.warning("Malformed LyX document: Could not find end of space inset.")
2585 del document.body[j]
2586 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2587 '\\begin_inset ERT\nstatus collapsed\n\n' \
2588 '\\begin_layout Standard\n\n\n\\backslash\n' \
2589 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2590 subst = subst.split('\n')
2591 document.body[i : i+1] = subst
2595 def revert_local_layout(document):
2596 ' Revert local layout headers.'
2599 i = find_token(document.header, "\\begin_local_layout", i)
2602 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2604 # this should not happen
2606 document.header[i : j + 1] = []
2609 def convert_pagebreaks(document):
2610 ' Convert inline Newpage insets to new format '
2613 i = find_token(document.body, '\\newpage', i)
2616 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2620 i = find_token(document.body, '\\pagebreak', i)
2623 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2627 i = find_token(document.body, '\\clearpage', i)
2630 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2634 i = find_token(document.body, '\\cleardoublepage', i)
2637 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2641 def revert_pagebreaks(document):
2642 ' Revert \\begin_inset Newpage to previous inline format '
2645 i = find_token(document.body, '\\begin_inset Newpage', i)
2648 j = find_end_of_inset(document.body, i)
2650 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2652 del document.body[j]
2653 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2654 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2655 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2656 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2659 def convert_linebreaks(document):
2660 ' Convert inline Newline insets to new format '
2663 i = find_token(document.body, '\\newline', i)
2666 document.body[i:i+1] = ['\\begin_inset Newline newline',
2670 i = find_token(document.body, '\\linebreak', i)
2673 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2677 def revert_linebreaks(document):
2678 ' Revert \\begin_inset Newline to previous inline format '
2681 i = find_token(document.body, '\\begin_inset Newline', i)
2684 j = find_end_of_inset(document.body, i)
2686 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2688 del document.body[j]
2689 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2690 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2693 def convert_japanese_plain(document):
2694 ' Set language japanese-plain to japanese '
2696 if document.language == "japanese-plain":
2697 document.language = "japanese"
2698 i = find_token(document.header, "\\language", 0)
2700 document.header[i] = "\\language japanese"
2703 j = find_token(document.body, "\\lang japanese-plain", j)
2706 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2710 def revert_pdfpages(document):
2711 ' Revert pdfpages external inset to ERT '
2714 i = find_token(document.body, "\\begin_inset External", i)
2717 j = find_end_of_inset(document.body, i)
2719 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2722 if get_value(document.body, 'template', i, j) == "PDFPages":
2723 filename = get_value(document.body, 'filename', i, j)
2725 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2726 for k in range(i, j):
2727 m = r.match(document.body[k])
2730 angle = get_value(document.body, 'rotateAngle', i, j)
2731 width = get_value(document.body, 'width', i, j)
2732 height = get_value(document.body, 'height', i, j)
2733 scale = get_value(document.body, 'scale', i, j)
2734 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2738 options += ",angle=" + angle
2740 options += "angle=" + angle
2743 options += ",width=" + convert_len(width)
2745 options += "width=" + convert_len(width)
2748 options += ",height=" + convert_len(height)
2750 options += "height=" + convert_len(height)
2753 options += ",scale=" + scale
2755 options += "scale=" + scale
2756 if keepAspectRatio != '':
2758 options += ",keepaspectratio"
2760 options += "keepaspectratio"
2762 options = '[' + options + ']'
2763 del document.body[i+1:j+1]
2764 document.body[i:i+1] = ['\\begin_inset ERT',
2767 '\\begin_layout Standard',
2770 'includepdf' + options + '{' + filename + '}',
2774 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2780 def revert_mexican(document):
2781 ' Set language Spanish(Mexico) to Spanish '
2783 if document.language == "spanish-mexico":
2784 document.language = "spanish"
2785 i = find_token(document.header, "\\language", 0)
2787 document.header[i] = "\\language spanish"
2790 j = find_token(document.body, "\\lang spanish-mexico", j)
2793 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2797 def remove_embedding(document):
2798 ' Remove embed tag from all insets '
2799 revert_inset_embedding(document, 'Graphics')
2800 revert_inset_embedding(document, 'External')
2801 revert_inset_embedding(document, 'CommandInset include')
2802 revert_inset_embedding(document, 'CommandInset bibtex')
2805 def revert_master(document):
2806 ' Remove master param '
2807 i = find_token(document.header, "\\master", 0)
2809 del document.header[i]
2812 def revert_graphics_group(document):
2813 ' Revert group information from graphics insets '
2816 i = find_token(document.body, "\\begin_inset Graphics", i)
2819 j = find_end_of_inset(document.body, i)
2821 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2824 k = find_token(document.body, " groupId", i, j)
2828 del document.body[k]
2832 def update_apa_styles(document):
2833 ' Replace obsolete styles '
2835 if document.textclass != "apa":
2838 obsoletedby = { "Acknowledgments": "Acknowledgements",
2839 "Section*": "Section",
2840 "Subsection*": "Subsection",
2841 "Subsubsection*": "Subsubsection",
2842 "Paragraph*": "Paragraph",
2843 "Subparagraph*": "Subparagraph"}
2846 i = find_token(document.body, "\\begin_layout", i)
2850 layout = document.body[i][14:]
2851 if layout in obsoletedby:
2852 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2857 def convert_paper_sizes(document):
2858 ' exchange size options legalpaper and executivepaper to correct order '
2859 # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2862 i = find_token(document.header, "\\papersize executivepaper", 0)
2864 document.header[i] = "\\papersize legalpaper"
2866 j = find_token(document.header, "\\papersize legalpaper", 0)
2868 document.header[j] = "\\papersize executivepaper"
2871 def revert_paper_sizes(document):
2872 ' exchange size options legalpaper and executivepaper to correct order '
2875 i = find_token(document.header, "\\papersize executivepaper", 0)
2877 document.header[i] = "\\papersize legalpaper"
2879 j = find_token(document.header, "\\papersize legalpaper", 0)
2881 document.header[j] = "\\papersize executivepaper"
2884 def convert_InsetSpace(document):
2885 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2888 i = find_token(document.body, "\\begin_inset Space", i)
2891 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2894 def revert_InsetSpace(document):
2895 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2898 i = find_token(document.body, "\\begin_inset space", i)
2901 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2904 def convert_display_enum(document):
2905 " Convert 'display foo' to 'display false/true'"
2908 i = find_token(document.body, "\tdisplay", i)
2911 val = get_value(document.body, 'display', i)
2913 document.body[i] = document.body[i].replace('none', 'false')
2914 if val == "default":
2915 document.body[i] = document.body[i].replace('default', 'true')
2916 if val == "monochrome":
2917 document.body[i] = document.body[i].replace('monochrome', 'true')
2918 if val == "grayscale":
2919 document.body[i] = document.body[i].replace('grayscale', 'true')
2921 document.body[i] = document.body[i].replace('color', 'true')
2922 if val == "preview":
2923 document.body[i] = document.body[i].replace('preview', 'true')
2927 def revert_display_enum(document):
2928 " Revert 'display false/true' to 'display none/color'"
2931 i = find_token(document.body, "\tdisplay", i)
2934 val = get_value(document.body, 'display', i)
2936 document.body[i] = document.body[i].replace('false', 'none')
2938 document.body[i] = document.body[i].replace('true', 'default')
2942 def remove_fontsCJK(document):
2943 ' Remove font_cjk param '
2944 i = find_token(document.header, "\\font_cjk", 0)
2946 del document.header[i]
2949 def convert_plain_layout(document):
2950 " Convert 'PlainLayout' to 'Plain Layout'"
2953 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2956 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2957 '\\begin_layout Plain Layout')
2961 def revert_plain_layout(document):
2962 " Revert 'Plain Layout' to 'PlainLayout'"
2965 i = find_token(document.body, '\\begin_layout Plain Layout', i)
2968 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2969 '\\begin_layout PlainLayout')
2973 def revert_plainlayout(document):
2974 " Revert 'PlainLayout' to 'Standard'"
2977 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2980 # This will be incorrect for some document classes, since Standard is not always
2981 # the default. But (a) it is probably the best we can do and (b) it will actually
2982 # work, in fact, since an unknown layout will be converted to default.
2983 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2984 '\\begin_layout Standard')
2988 def revert_polytonicgreek(document):
2989 "Set language polytonic Greek to Greek"
2991 if document.language == "polutonikogreek":
2992 document.language = "greek"
2993 i = find_token(document.header, "\\language", 0)
2995 document.header[i] = "\\language greek"
2998 j = find_token(document.body, "\\lang polutonikogreek", j)
3001 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
3005 def revert_removed_modules(document):
3008 i = find_token(document.header, "\\begin_remove_modules", i)
3011 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
3013 # this should not happen
3015 document.header[i : j + 1] = []
3018 def add_plain_layout(document):
3021 i = find_token(document.body, "\\begin_layout", i)
3024 if len(document.body[i].split()) == 1:
3025 document.body[i] = "\\begin_layout Plain Layout"
3029 def revert_tabulators(document):
3030 "Revert tabulators to 4 spaces"
3033 i = find_token(document.body, "\t", i)
3036 document.body[i] = document.body[i].replace("\t", " ")
3040 def revert_tabsize(document):
3041 "Revert the tabsize parameter of listings"
3045 # either it is the only parameter
3046 i = find_token(document.body, 'lstparams "tabsize=4"', i)
3048 del document.body[i]
3050 j = find_token(document.body, "lstparams", j)
3053 pos = document.body[j].find(",tabsize=")
3054 document.body[j] = document.body[j][:pos] + '"'
3059 def revert_mongolian(document):
3060 "Set language Mongolian to English"
3062 if document.language == "mongolian":
3063 document.language = "english"
3064 i = find_token(document.header, "\\language", 0)
3066 document.header[i] = "\\language english"
3069 j = find_token(document.body, "\\lang mongolian", j)
3072 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
3076 def revert_default_options(document):
3077 ' Remove param use_default_options '
3078 i = find_token(document.header, "\\use_default_options", 0)
3080 del document.header[i]
3083 def convert_default_options(document):
3084 ' Add param use_default_options and set it to false '
3085 i = find_token(document.header, "\\textclass", 0)
3087 document.warning("Malformed LyX document: Missing `\\textclass'.")
3089 document.header.insert(i, '\\use_default_options false')
3092 def revert_backref_options(document):
3093 ' Revert option pdf_backref=page to pagebackref '
3094 i = find_token(document.header, "\\pdf_backref page", 0)
3096 document.header[i] = "\\pdf_pagebackref true"
3099 def convert_backref_options(document):
3100 ' We have changed the option pagebackref to backref=true '
3101 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3103 document.header[i] = "\\pdf_backref page"
3104 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3106 del document.header[j]
3107 # backref=true was not a valid option, we meant backref=section
3108 k = find_token(document.header, "\\pdf_backref true", 0)
3109 if k != -1 and i != -1:
3110 del document.header[k]
3111 elif k != -1 and j != -1:
3112 document.header[k] = "\\pdf_backref section"
3115 def convert_charstyle_element(document):
3116 "Convert CharStyle to Element for docbook backend"
3117 if document.backend != "docbook":
3121 i = find_token(document.body, "\\begin_inset Flex CharStyle:", i)
3124 document.body[i] = document.body[i].replace('\\begin_inset Flex CharStyle:',
3125 '\\begin_inset Flex Element:')
3127 def revert_charstyle_element(document):
3128 "Convert Element to CharStyle for docbook backend"
3129 if document.backend != "docbook":
3133 i = find_token(document.body, "\\begin_inset Flex Element:", i)
3136 document.body[i] = document.body[i].replace('\\begin_inset Flex Element:',
3137 '\\begin_inset Flex CharStyle:')
3143 supported_versions = ["1.6.0","1.6"]
3144 convert = [[277, [fix_wrong_tables]],
3145 [278, [close_begin_deeper]],
3146 [279, [long_charstyle_names]],
3147 [280, [axe_show_label]],
3150 [283, [convert_flex]],
3154 [287, [convert_wrapfig_options]],
3155 [288, [convert_inset_command]],
3156 [289, [convert_latexcommand_index]],
3159 [292, [convert_japanese_cjk]],
3161 [294, [convert_pdf_options]],
3162 [295, [convert_htmlurl, convert_url]],
3163 [296, [convert_include]],
3164 [297, [convert_usorbian]],
3165 [298, [convert_macro_global]],
3170 [303, [convert_serbocroatian]],
3171 [304, [convert_framed_notes]],
3178 [311, [convert_ams_classes]],
3180 [313, [convert_module_names]],
3183 [316, [convert_subfig]],
3186 [319, [convert_spaceinset, convert_hfill]],
3188 [321, [convert_tablines]],
3189 [322, [convert_plain_layout]],
3190 [323, [convert_pagebreaks]],
3191 [324, [convert_linebreaks]],
3192 [325, [convert_japanese_plain]],
3195 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3198 [331, [convert_ltcaption]],
3200 [333, [update_apa_styles]],
3201 [334, [convert_paper_sizes]],
3202 [335, [convert_InsetSpace]],
3204 [337, [convert_display_enum]],
3207 [340, [add_plain_layout]],
3210 [343, [convert_default_options]],
3211 [344, [convert_backref_options]],
3212 [345, [convert_charstyle_element]]
3215 revert = [[344, [revert_charstyle_element]],
3216 [343, [revert_backref_options]],
3217 [342, [revert_default_options]],
3218 [341, [revert_mongolian]],
3219 [340, [revert_tabulators, revert_tabsize]],
3221 [338, [revert_removed_modules]],
3222 [337, [revert_polytonicgreek]],
3223 [336, [revert_display_enum]],
3224 [335, [remove_fontsCJK]],
3225 [334, [revert_InsetSpace]],
3226 [333, [revert_paper_sizes]],
3228 [331, [revert_graphics_group]],
3229 [330, [revert_ltcaption]],
3230 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
3231 [328, [revert_master]],
3233 [326, [revert_mexican]],
3234 [325, [revert_pdfpages]],
3236 [323, [revert_linebreaks]],
3237 [322, [revert_pagebreaks]],
3238 [321, [revert_local_layout, revert_plain_layout]],
3239 [320, [revert_tablines]],
3240 [319, [revert_protected_hfill]],
3241 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3242 [317, [remove_extra_embedded_files]],
3243 [316, [revert_wrapplacement]],
3244 [315, [revert_subfig]],
3245 [314, [revert_colsep, revert_plainlayout]],
3247 [312, [revert_module_names]],
3248 [311, [revert_rotfloat, revert_widesideways]],
3249 [310, [revert_external_embedding]],
3250 [309, [revert_btprintall]],
3251 [308, [revert_nocite]],
3252 [307, [revert_serbianlatin]],
3253 [306, [revert_slash, revert_nobreakdash]],
3254 [305, [revert_interlingua]],
3255 [304, [revert_bahasam]],
3256 [303, [revert_framed_notes]],
3258 [301, [revert_latin, revert_samin]],
3259 [300, [revert_linebreak]],
3260 [299, [revert_pagebreak]],
3261 [298, [revert_hyperlinktype]],
3262 [297, [revert_macro_optional_params]],
3263 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3264 [295, [revert_include]],
3265 [294, [revert_href, revert_url]],
3266 [293, [revert_pdf_options_2]],
3267 [292, [revert_inset_info]],
3268 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3269 [290, [revert_vietnamese]],
3270 [289, [revert_wraptable]],
3271 [288, [revert_latexcommand_index]],
3272 [287, [revert_inset_command]],
3273 [286, [revert_wrapfig_options]],
3274 [285, [revert_pdf_options]],
3275 [284, [remove_inzip_options]],
3277 [282, [revert_flex]],
3279 [280, [revert_begin_modules]],
3280 [279, [revert_show_label]],
3281 [278, [revert_long_charstyle_names]],
3287 if __name__ == "__main__":