1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2008 The LyX Team <lyx-devel@lists.lyx.org>
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 """ Convert files to the file format generated by lyx 1.6"""
25 from parser_tools import find_token, find_end_of, find_tokens, get_value, get_value_string
27 ####################################################################
28 # Private helper functions
30 def find_end_of_inset(lines, i):
31 " Find end of inset, where lines[i] is included."
32 return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
36 # document.body[i] = wrap_insert_ert(...)
37 # wrap_into_ert may returns a multiline string, which should NOT appear
38 # in document.body. Insetad, do something like this:
39 # subst = wrap_inset_ert(...)
40 # subst = subst.split('\n')
41 # document.body[i:i+1] = subst
43 # where the last statement resets the counter to accord with the added
45 def wrap_into_ert(string, src, dst):
46 '''Within string, replace occurrences of src with dst, wrapped into ERT
47 E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is:
48 sch<ERT>\\backslash</ERT>"on'''
49 return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
50 + dst + '\n\\end_layout\n\\end_inset\n')
52 def put_cmd_in_ert(string):
53 for rep in unicode_reps:
54 string = string.replace(rep[1], rep[0].replace('\\\\', '\\'))
55 string = string.replace('\\', "\\backslash\n")
56 string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n" \
57 + string + "\n\\end_layout\n\\end_inset"
60 def add_to_preamble(document, text):
61 """ Add text to the preamble if it is not already there.
62 Only the first line is checked!"""
64 if find_token(document.preamble, text[0], 0) != -1:
67 document.preamble.extend(text)
69 def insert_to_preamble(index, document, text):
70 """ Insert text to the preamble at a given line"""
72 document.preamble.insert(index, text)
74 # Convert a LyX length into a LaTeX length
76 units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
77 "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
78 "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
80 # Convert LyX units to LaTeX units
81 for unit in units.keys():
82 if len.find(unit) != -1:
83 len = '%f' % (len2value(len) / 100)
84 len = len.strip('0') + units[unit]
89 # Return the value of len without the unit in numerical form.
91 result = re.search('([+-]?[0-9.]+)', len)
93 return float(result.group(1))
97 # Unfortunately, this doesn't really work, since Standard isn't always default.
98 # But it's as good as we can do right now.
99 def find_default_layout(document, start, end):
100 l = find_token(document.body, "\\begin_layout Standard", start, end)
102 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
104 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
107 def get_option(document, m, option, default):
108 l = document.body[m].find(option)
111 val = document.body[m][l:].split('"')[1]
114 def remove_option(document, m, option):
115 l = document.body[m].find(option)
117 val = document.body[m][l:].split('"')[1]
118 document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
121 def set_option(document, m, option, value):
122 l = document.body[m].find(option)
124 oldval = document.body[m][l:].split('"')[1]
125 l = l + len(option + '="')
126 document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
128 document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
132 def read_unicodesymbols():
133 " Read the unicodesymbols list of unicode characters and corresponding commands."
134 pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
135 fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
137 # Two backslashes, followed by some non-word character, and then a character
138 # in brackets. The idea is to check for constructs like: \"{u}, which is how
139 # they are written in the unicodesymbols file; but they can also be written
140 # as: \"u or even \" u.
141 r = re.compile(r'\\\\(\W)\{(\w)\}')
142 for line in fp.readlines():
143 if line[0] != '#' and line.strip() != "":
144 line=line.replace(' "',' ') # remove all quotation marks with spaces before
145 line=line.replace('" ',' ') # remove all quotation marks with spaces after
146 line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
148 [ucs4,command,dead] = line.split(None,2)
149 if command[0:1] != "\\":
151 spec_chars.append([command, unichr(eval(ucs4))])
157 # If the character is a double-quote, then we need to escape it, too,
158 # since it is done that way in the LyX file.
159 if m.group(1) == "\"":
162 command += m.group(1) + m.group(2)
163 commandbl += m.group(1) + ' ' + m.group(2)
164 spec_chars.append([command, unichr(eval(ucs4))])
165 spec_chars.append([commandbl, unichr(eval(ucs4))])
170 def extract_argument(line):
171 'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
176 bracere = re.compile("(\s*)(.*)")
177 n = bracere.match(line)
178 whitespace = n.group(1)
181 if brace != "[" and brace != "{":
205 # We never found the matching brace
206 # So, to be on the safe side, let's just return everything
207 # which will then get wrapped as ERT
209 return (line[:pos + 1], line[pos + 1:])
212 def latex2ert(line, isindex):
213 '''Converts LaTeX commands into ERT. line may well be a multi-line
214 string when it is returned.'''
219 ## FIXME Escaped \ ??
220 # This regex looks for a LaTeX command---i.e., something of the form
221 # "\alPhaStuFF", or "\X", where X is any character---where the command
222 # may also be preceded by an additional backslash, which is how it would
223 # appear (e.g.) in an InsetIndex.
224 labelre = re.compile(r'(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)')
226 m = labelre.match(line)
233 (arg, rest) = extract_argument(end)
238 # If we wanted to put labels into an InsetLabel, for example, then we
239 # would just need to test here for cmd == "label" and then take some
240 # appropriate action, i.e., to use arg to get the content and then
241 # wrap it appropriately.
242 cmd = put_cmd_in_ert(cmd)
243 retval += "\n" + cmd + "\n"
245 m = labelre.match(line)
246 # put all remaining braces in ERT
247 line = wrap_into_ert(line, '}', '}')
248 line = wrap_into_ert(line, '{', '{')
250 # active character that is not available in all font encodings
251 line = wrap_into_ert(line, '|', '|')
256 unicode_reps = read_unicodesymbols()
259 #Might should do latex2ert first, then deal with stuff that DOESN'T
260 #end up inside ERT. That routine could be modified so that it returned
261 #a list of lines, and we could then skip ERT bits and only deal with
263 def latex2lyx(data, isindex):
264 '''Takes a string, possibly multi-line, and returns the result of
265 converting LaTeX constructs into LyX constructs. Returns a list of
266 lines, suitable for insertion into document.body.
267 The bool isindex specifies whether we are in an index macro (which
268 has some specific active characters that need to be ERTed).'''
274 # Convert LaTeX to Unicode
275 # Commands of this sort need to be checked to make sure they are
276 # followed by a non-alpha character, lest we replace too much.
277 hardone = re.compile(r'^\\\\[a-zA-Z]+$')
279 for rep in unicode_reps:
280 if hardone.match(rep[0]):
283 pos = data.find(rep[0], pos)
286 nextpos = pos + len(rep[0])
287 if nextpos < len(data) and data[nextpos].isalpha():
288 # not the end of that command
291 data = data[:pos] + rep[1] + data[nextpos:]
294 data = data.replace(rep[0], rep[1])
298 data = wrap_into_ert(data, r'\"', '"')
300 data = data.replace('\\\\', '\\')
303 mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
304 lines = data.split('\n')
306 #document.warning("LINE: " + line)
307 #document.warning(str(i) + ":" + document.body[i])
308 #document.warning("LAST: " + document.body[-1])
313 f = m.group(2).replace('\\\\', '\\')
317 s = latex2ert(s, isindex)
318 subst = s.split('\n')
320 retval.append("\\begin_inset Formula " + f)
321 retval.append("\\end_inset")
323 # Handle whatever is left, which is just text
324 g = latex2ert(g, isindex)
325 subst = g.split('\n')
330 def lyxline2latex(document, line, inert):
331 'Convert some LyX stuff into corresponding LaTeX stuff line-wise, as best we can.'
332 if line.startswith("\\begin_inset Formula"):
334 elif line.startswith("\\begin_inset Quotes"):
335 # For now, we do a very basic reversion. Someone who understands
336 # quotes is welcome to fix it up.
337 qtype = line[20:].strip()
351 elif line.isspace() or \
352 line.startswith("\\begin_layout") or \
353 line.startswith("\\end_layout") or \
354 line.startswith("\\begin_inset") or \
355 line.startswith("\\end_inset") or \
356 line.startswith("\\lang") or \
357 line.strip() == "status collapsed" or \
358 line.strip() == "status open":
362 # this needs to be added to the preamble because of cases like
363 # \textmu, \textbackslash, etc.
364 add_to_preamble(document, ['% added by lyx2lyx for converted entries',
365 '\\@ifundefined{textmu}',
366 ' {\\usepackage{textcomp}}{}'])
367 # a lossless reversion is not possible
368 # try at least to handle some common insets and settings
370 line = line.replace(r'\backslash', '\\')
372 line = line.replace('&', '\\&{}')
373 line = line.replace('#', '\\#{}')
374 line = line.replace('^', '\\^{}')
375 line = line.replace('%', '\\%{}')
376 line = line.replace('_', '\\_{}')
377 line = line.replace('$', '\\${}')
379 # Do the LyX text --> LaTeX conversion
380 for rep in unicode_reps:
381 line = line.replace(rep[1], rep[0].replace('\\\\', '\\') + "{}")
382 line = line.replace(r'\backslash', r'\textbackslash{}')
383 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
384 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
385 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
386 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
387 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
388 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
389 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
390 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
391 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
395 def lyx2latex(document, lines):
396 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
397 # clean up multiline stuff
401 for curline in range(len(lines)):
402 line = lines[curline]
403 if line.startswith("\\begin_inset ERT"):
404 # We don't want to replace things inside ERT, so figure out
405 # where the end of the inset is.
406 ert_end = find_end_of_inset(lines, curline + 1)
408 inert = ert_end >= curline
409 content += lyxline2latex(document, lines[curline], inert)
414 ####################################################################
416 def convert_ltcaption(document):
419 i = find_token(document.body, "\\begin_inset Tabular", i)
422 j = find_end_of_inset(document.body, i + 1)
424 document.warning("Malformed LyX document: Could not find end of tabular.")
427 nrows = int(document.body[i+1].split('"')[3])
428 ncols = int(document.body[i+1].split('"')[5])
431 for k in range(nrows):
432 m = find_token(document.body, "<row", m)
435 for k in range(ncols):
436 m = find_token(document.body, "<cell", m)
438 mend = find_token(document.body, "</cell>", m + 1)
439 # first look for caption insets
440 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
441 # then look for ERT captions
443 mcap = find_token(document.body, "caption", m + 1, mend)
445 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
448 if caption == 'true':
450 set_option(document, r, 'caption', 'true')
451 set_option(document, m, 'multicolumn', '1')
452 set_option(document, m, 'bottomline', 'false')
453 set_option(document, m, 'topline', 'false')
454 set_option(document, m, 'rightline', 'false')
455 set_option(document, m, 'leftline', 'false')
456 #j = find_end_of_inset(document.body, j + 1)
458 set_option(document, m, 'multicolumn', '2')
465 #FIXME Use of wrap_into_ert can confuse lyx2lyx
466 def revert_ltcaption(document):
469 i = find_token(document.body, "\\begin_inset Tabular", i)
472 j = find_end_of_inset(document.body, i + 1)
474 document.warning("Malformed LyX document: Could not find end of tabular.")
479 nrows = int(document.body[i+1].split('"')[3])
480 ncols = int(document.body[i+1].split('"')[5])
482 for k in range(nrows):
483 m = find_token(document.body, "<row", m)
484 caption = get_option(document, m, 'caption', 'false')
485 if caption == 'true':
486 remove_option(document, m, 'caption')
487 for k in range(ncols):
488 m = find_token(document.body, "<cell", m)
489 remove_option(document, m, 'multicolumn')
491 m = find_token(document.body, "\\begin_inset Caption", m)
494 m = find_end_of_inset(document.body, m + 1)
495 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
501 def convert_tablines(document):
504 i = find_token(document.body, "\\begin_inset Tabular", i)
506 # LyX 1.3 inserted an extra space between \begin_inset
507 # and Tabular so let us try if this is the case and fix it.
508 i = find_token(document.body, "\\begin_inset Tabular", i)
512 document.body[i] = "\\begin_inset Tabular"
513 j = find_end_of_inset(document.body, i + 1)
515 document.warning("Malformed LyX document: Could not find end of tabular.")
519 nrows = int(document.body[i+1].split('"')[3])
520 ncols = int(document.body[i+1].split('"')[5])
523 for k in range(ncols):
524 m = find_token(document.body, "<column", m)
525 left = get_option(document, m, 'leftline', 'false')
526 right = get_option(document, m, 'rightline', 'false')
527 col_info.append([left, right])
528 remove_option(document, m, 'leftline')
529 remove_option(document, m, 'rightline')
533 for k in range(nrows):
534 m = find_token(document.body, "<row", m)
535 top = get_option(document, m, 'topline', 'false')
536 bottom = get_option(document, m, 'bottomline', 'false')
537 row_info.append([top, bottom])
538 remove_option(document, m, 'topline')
539 remove_option(document, m, 'bottomline')
544 for k in range(nrows*ncols):
545 m = find_token(document.body, "<cell", m)
546 mc_info.append(get_option(document, m, 'multicolumn', '0'))
549 for l in range(nrows):
550 for k in range(ncols):
551 m = find_token(document.body, '<cell', m)
552 if mc_info[l*ncols + k] == '0':
553 r = set_option(document, m, 'topline', row_info[l][0])
554 r = set_option(document, m, 'bottomline', row_info[l][1])
555 r = set_option(document, m, 'leftline', col_info[k][0])
556 r = set_option(document, m, 'rightline', col_info[k][1])
557 elif mc_info[l*ncols + k] == '1':
559 while s < ncols and mc_info[l*ncols + s] == '2':
561 if s < ncols and mc_info[l*ncols + s] != '1':
562 r = set_option(document, m, 'rightline', col_info[k][1])
563 if k > 0 and mc_info[l*ncols + k - 1] == '0':
564 r = set_option(document, m, 'leftline', col_info[k][0])
569 def revert_tablines(document):
572 i = find_token(document.body, "\\begin_inset Tabular", i)
575 j = find_end_of_inset(document.body, i)
577 document.warning("Malformed LyX document: Could not find end of tabular.")
582 nrows = int(document.body[i+1].split('"')[3])
583 ncols = int(document.body[i+1].split('"')[5])
586 for k in range(nrows*ncols):
587 m = find_token(document.body, "<cell", m)
588 top = get_option(document, m, 'topline', 'false')
589 bottom = get_option(document, m, 'bottomline', 'false')
590 left = get_option(document, m, 'leftline', 'false')
591 right = get_option(document, m, 'rightline', 'false')
592 lines.append([top, bottom, left, right])
595 # we will want to ignore longtable captions
598 for k in range(nrows):
599 m = find_token(document.body, "<row", m)
600 caption = get_option(document, m, 'caption', 'false')
601 caption_info.append([caption])
606 for k in range(ncols):
607 m = find_token(document.body, "<column", m)
609 for l in range(nrows):
610 left = lines[l*ncols + k][2]
611 if left == 'false' and caption_info[l] == 'false':
613 set_option(document, m, 'leftline', left)
615 for l in range(nrows):
616 right = lines[l*ncols + k][3]
617 if right == 'false' and caption_info[l] == 'false':
619 set_option(document, m, 'rightline', right)
623 for k in range(nrows):
624 m = find_token(document.body, "<row", m)
626 for l in range(ncols):
627 top = lines[k*ncols + l][0]
630 if caption_info[k] == 'false':
632 set_option(document, m, 'topline', top)
634 for l in range(ncols):
635 bottom = lines[k*ncols + l][1]
636 if bottom == 'false':
638 if caption_info[k] == 'false':
640 set_option(document, m, 'bottomline', bottom)
646 def fix_wrong_tables(document):
649 i = find_token(document.body, "\\begin_inset Tabular", i)
652 j = find_end_of_inset(document.body, i + 1)
654 document.warning("Malformed LyX document: Could not find end of tabular.")
658 nrows = int(document.body[i+1].split('"')[3])
659 ncols = int(document.body[i+1].split('"')[5])
661 for l in range(nrows):
663 for k in range(ncols):
664 m = find_token(document.body, '<cell', m)
666 if document.body[m].find('multicolumn') != -1:
667 multicol_cont = int(document.body[m].split('"')[1])
669 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
670 document.body[m] = document.body[m][:5] + document.body[m][21:]
673 prev_multicolumn = multicol_cont
680 def close_begin_deeper(document):
684 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
689 if document.body[i][:13] == "\\begin_deeper":
696 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
699 def long_charstyle_names(document):
702 i = find_token(document.body, "\\begin_inset CharStyle", i)
705 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
708 def revert_long_charstyle_names(document):
711 i = find_token(document.body, "\\begin_inset CharStyle", i)
714 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
718 def axe_show_label(document):
721 i = find_token(document.body, "\\begin_inset CharStyle", i)
724 if document.body[i + 1].find("show_label") != -1:
725 if document.body[i + 1].find("true") != -1:
726 document.body[i + 1] = "status open"
727 del document.body[ i + 2]
729 if document.body[i + 1].find("false") != -1:
730 document.body[i + 1] = "status collapsed"
731 del document.body[ i + 2]
733 document.warning("Malformed LyX document: show_label neither false nor true.")
735 document.warning("Malformed LyX document: show_label missing in CharStyle.")
740 def revert_show_label(document):
743 i = find_token(document.body, "\\begin_inset CharStyle", i)
746 if document.body[i + 1].find("status open") != -1:
747 document.body.insert(i + 1, "show_label true")
749 if document.body[i + 1].find("status collapsed") != -1:
750 document.body.insert(i + 1, "show_label false")
752 document.warning("Malformed LyX document: no legal status line in CharStyle.")
755 def revert_begin_modules(document):
758 i = find_token(document.header, "\\begin_modules", i)
761 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
763 # this should not happen
765 document.header[i : j + 1] = []
767 def convert_flex(document):
768 "Convert CharStyle to Flex"
771 i = find_token(document.body, "\\begin_inset CharStyle", i)
774 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
776 def revert_flex(document):
777 "Convert Flex to CharStyle"
780 i = find_token(document.body, "\\begin_inset Flex", i)
783 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
786 def revert_pdf_options(document):
787 "Revert PDF options for hyperref."
788 # store the PDF options and delete the entries from the Lyx file
796 bookmarksnumbered = ""
798 bookmarksopenlevel = ""
806 i = find_token(document.header, "\\use_hyperref", i)
808 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
809 del document.header[i]
810 i = find_token(document.header, "\\pdf_store_options", i)
812 del document.header[i]
813 i = find_token(document.header, "\\pdf_title", 0)
815 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
816 title = ' pdftitle={' + title + '}'
817 del document.header[i]
818 i = find_token(document.header, "\\pdf_author", 0)
820 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
822 author = ' pdfauthor={' + author + '}'
824 author = ',\n pdfauthor={' + author + '}'
825 del document.header[i]
826 i = find_token(document.header, "\\pdf_subject", 0)
828 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
829 if title == "" and author == "":
830 subject = ' pdfsubject={' + subject + '}'
832 subject = ',\n pdfsubject={' + subject + '}'
833 del document.header[i]
834 i = find_token(document.header, "\\pdf_keywords", 0)
836 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
837 if title == "" and author == "" and subject == "":
838 keywords = ' pdfkeywords={' + keywords + '}'
840 keywords = ',\n pdfkeywords={' + keywords + '}'
841 del document.header[i]
842 i = find_token(document.header, "\\pdf_bookmarks", 0)
844 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
845 bookmarks = ',\n bookmarks=' + bookmarks
846 del document.header[i]
847 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
849 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
850 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
851 del document.header[i]
852 i = find_token(document.header, "\\pdf_bookmarksopen", i)
854 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
855 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
856 del document.header[i]
857 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
859 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
860 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
861 del document.header[i]
862 i = find_token(document.header, "\\pdf_breaklinks", i)
864 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
865 breaklinks = ',\n breaklinks=' + breaklinks
866 del document.header[i]
867 i = find_token(document.header, "\\pdf_pdfborder", i)
869 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
870 if pdfborder == 'true':
871 pdfborder = ',\n pdfborder={0 0 0}'
873 pdfborder = ',\n pdfborder={0 0 1}'
874 del document.header[i]
875 i = find_token(document.header, "\\pdf_colorlinks", i)
877 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
878 colorlinks = ',\n colorlinks=' + colorlinks
879 del document.header[i]
880 i = find_token(document.header, "\\pdf_backref", i)
882 backref = get_value_string(document.header, '\\pdf_backref', 0)
883 backref = ',\n backref=' + backref
884 del document.header[i]
885 i = find_token(document.header, "\\pdf_pagebackref", i)
887 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
888 pagebackref = ',\n pagebackref=' + pagebackref
889 del document.header[i]
890 i = find_token(document.header, "\\pdf_pagemode", 0)
892 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
893 pagemode = ',\n pdfpagemode=' + pagemode
894 del document.header[i]
895 i = find_token(document.header, "\\pdf_quoted_options", 0)
897 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
898 if title == "" and author == "" and subject == "" and keywords == "":
899 otheroptions = ' ' + otheroptions
901 otheroptions = ',\n ' + otheroptions
902 del document.header[i]
904 # write to the preamble when hyperref was used
906 # preamble write preparations
907 # bookmark numbers are only output when they are turned on
908 if bookmarksopen == ',\n bookmarksopen=true':
909 bookmarksopen = bookmarksopen + bookmarksopenlevel
910 if bookmarks == ',\n bookmarks=true':
911 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
913 bookmarks = bookmarks
914 # hypersetup is only output when there are things to be set up
915 setupstart = '\\hypersetup{%\n'
917 if otheroptions == "" and title == "" and author == ""\
918 and subject == "" and keywords == "":
922 # babel must be loaded before hyperref and hyperref the first part
923 # of the preamble, like in LyX 1.6
924 insert_to_preamble(0, document,
925 '% Commands inserted by lyx2lyx for PDF properties\n'
926 + '\\usepackage{babel}\n'
927 + '\\usepackage[unicode=true'
946 def remove_inzip_options(document):
947 "Remove inzipName and embed options from the Graphics inset"
950 i = find_token(document.body, "\\begin_inset Graphics", i)
953 j = find_end_of_inset(document.body, i + 1)
956 document.warning("Malformed LyX document: Could not find end of graphics inset.")
957 # If there's a inzip param, just remove that
958 k = find_token(document.body, "\tinzipName", i + 1, j)
961 # embed option must follow the inzipName option
962 del document.body[k+1]
966 def convert_inset_command(document):
969 \begin_inset LatexCommand cmd
971 \begin_inset CommandInset InsetType
976 i = find_token(document.body, "\\begin_inset LatexCommand", i)
979 line = document.body[i]
980 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
984 #this is adapted from factory.cpp
985 if cmdName[0:4].lower() == "cite":
986 insetName = "citation"
987 elif cmdName == "url" or cmdName == "htmlurl":
989 elif cmdName[-3:] == "ref":
991 elif cmdName == "tableofcontents":
993 elif cmdName == "printnomenclature":
994 insetName = "nomencl_print"
995 elif cmdName == "printindex":
996 insetName = "index_print"
999 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
1000 document.body[i : i+1] = insertion
1003 def revert_inset_command(document):
1006 \begin_inset CommandInset InsetType
1009 \begin_inset LatexCommand cmd
1010 Some insets may end up being converted to insets earlier versions of LyX
1011 will not be able to recognize. Not sure what to do about that.
1015 i = find_token(document.body, "\\begin_inset CommandInset", i)
1018 nextline = document.body[i+1]
1019 r = re.compile(r'LatexCommand\s+(.*)$')
1020 m = r.match(nextline)
1022 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
1025 cmdName = m.group(1)
1026 insertion = ["\\begin_inset LatexCommand " + cmdName]
1027 document.body[i : i+2] = insertion
1030 def convert_wrapfig_options(document):
1031 "Convert optional options for wrap floats (wrapfig)."
1032 # adds the tokens "lines", "placement", and "overhang"
1035 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1038 document.body.insert(i + 1, "lines 0")
1039 j = find_token(document.body, "placement", i)
1040 # placement can be already set or not; if not, set it
1042 document.body.insert(i + 3, "overhang 0col%")
1044 document.body.insert(i + 2, "placement o")
1045 document.body.insert(i + 3, "overhang 0col%")
1049 def revert_wrapfig_options(document):
1050 "Revert optional options for wrap floats (wrapfig)."
1053 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1056 j = find_end_of_inset(document.body, i)
1058 document.warning("Can't find end of Wrap inset at line " + str(i))
1061 k = find_default_layout(document, i, j)
1063 document.warning("Can't find default layout for Wrap figure!")
1066 # Options should be between i and k now
1067 l = find_token(document.body, "lines", i, k)
1069 document.warning("Can't find lines option for Wrap figure!")
1072 m = find_token(document.body, "overhang", i + 1, k)
1074 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1077 # Do these in reverse order
1078 del document.body[m]
1079 del document.body[l]
1083 def convert_latexcommand_index(document):
1084 "Convert from LatexCommand form to collapsable form."
1086 r1 = re.compile('name "(.*)"')
1088 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1091 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1094 j = find_end_of_inset(document.body, i + 1)
1096 document.warning("Unable to find end of index inset at line " + str(i) + "!")
1099 m = r1.match(document.body[i + 2])
1101 document.warning("Unable to match: " + document.body[i+2])
1102 # this can happen with empty index insets!
1105 fullcontent = m.group(1)
1106 linelist = latex2lyx(fullcontent, True)
1107 #document.warning(fullcontent)
1109 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1110 linelist + ["\\end_layout"]
1111 document.body[i : j] = linelist
1112 i += len(linelist) - (j - i)
1115 def revert_latexcommand_index(document):
1116 "Revert from collapsable form to LatexCommand form."
1119 i = find_token(document.body, "\\begin_inset Index", i)
1122 j = find_end_of_inset(document.body, i + 1)
1126 content = lyx2latex(document, document.body[i:j])
1128 content = content.replace('"', r'\"')
1129 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1130 "name " + '"' + content + '"', ""]
1134 def revert_wraptable(document):
1135 "Revert wrap table to wrap figure."
1138 i = find_token(document.body, "\\begin_inset Wrap table", i)
1141 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1145 def revert_vietnamese(document):
1146 "Set language Vietnamese to English"
1147 # Set document language from Vietnamese to English
1149 if document.language == "vietnamese":
1150 document.language = "english"
1151 i = find_token(document.header, "\\language", 0)
1153 document.header[i] = "\\language english"
1156 j = find_token(document.body, "\\lang vietnamese", j)
1159 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1163 def convert_japanese_cjk(document):
1164 "Set language japanese to japanese-cjk"
1165 # Set document language from japanese-plain to japanese
1167 if document.language == "japanese":
1168 document.language = "japanese-cjk"
1169 i = find_token(document.header, "\\language", 0)
1171 document.header[i] = "\\language japanese-cjk"
1174 j = find_token(document.body, "\\lang japanese", j)
1177 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1181 def revert_japanese(document):
1182 "Set language japanese-plain to japanese"
1183 # Set document language from japanese-plain to japanese
1185 if document.language == "japanese-plain":
1186 document.language = "japanese"
1187 i = find_token(document.header, "\\language", 0)
1189 document.header[i] = "\\language japanese"
1192 j = find_token(document.body, "\\lang japanese-plain", j)
1195 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1199 def revert_japanese_cjk(document):
1200 "Set language japanese-cjk to japanese"
1201 # Set document language from japanese-plain to japanese
1203 if document.language == "japanese-cjk":
1204 document.language = "japanese"
1205 i = find_token(document.header, "\\language", 0)
1207 document.header[i] = "\\language japanese"
1210 j = find_token(document.body, "\\lang japanese-cjk", j)
1213 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1217 def revert_japanese_encoding(document):
1218 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1219 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1221 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1223 document.header[i] = "\\inputencoding EUC-JP"
1225 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1227 document.header[j] = "\\inputencoding JIS"
1229 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1230 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1231 document.header[k] = "\\inputencoding UTF8"
1234 def revert_inset_info(document):
1235 'Replace info inset with its content'
1238 i = find_token(document.body, '\\begin_inset Info', i)
1241 j = find_end_of_inset(document.body, i + 1)
1244 document.warning("Malformed LyX document: Could not find end of Info inset.")
1247 for k in range(i, j+1):
1248 if document.body[k].startswith("arg"):
1249 arg = document.body[k][3:].strip()
1250 # remove embracing quotation marks
1253 if arg[len(arg) - 1] == '"':
1254 arg = arg[:len(arg) - 1]
1255 # \" to straight quote
1256 arg = arg.replace(r'\"', '"')
1258 arg = arg.replace(r'\\', "\\backslash\n")
1259 if document.body[k].startswith("type"):
1260 type = document.body[k][4:].strip().strip('"')
1261 # I think there is a newline after \\end_inset, which should be removed.
1262 if document.body[j + 1].strip() == "":
1263 document.body[i : (j + 2)] = [type + ':' + arg]
1265 document.body[i : (j + 1)] = [type + ':' + arg]
1268 def convert_pdf_options(document):
1269 # Set the pdfusetitle tag, delete the pdf_store_options,
1270 # set quotes for bookmarksopenlevel"
1271 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1273 k = find_token(document.header, "\\use_hyperref", 0)
1274 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1275 k = find_token(document.header, "\\pdf_store_options", 0)
1277 del document.header[k]
1278 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1280 document.header[i] = document.header[i].replace('"', '')
1283 def revert_pdf_options_2(document):
1284 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1285 k = find_token(document.header, "\\use_hyperref", 0)
1286 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1288 del document.header[i]
1289 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1291 values = document.header[i].split()
1292 values[1] = ' "' + values[1] + '"'
1293 document.header[i] = ''.join(values)
1296 def convert_htmlurl(document):
1297 'Convert "htmlurl" to "href" insets for docbook'
1298 if document.backend != "docbook":
1302 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1305 document.body[i] = "\\begin_inset CommandInset href"
1306 document.body[i + 1] = "LatexCommand href"
1310 def convert_url(document):
1311 'Convert url insets to url charstyles'
1312 if document.backend == "docbook":
1316 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1319 n = find_token(document.body, "name", i)
1321 # place the URL name in typewriter before the new URL insert
1322 # grab the name 'bla' from the e.g. the line 'name "bla"',
1323 # therefore start with the 6th character
1324 name = document.body[n][6:-1]
1325 newname = [name + " "]
1326 document.body[i:i] = newname
1328 j = find_token(document.body, "target", i)
1330 document.warning("Malformed LyX document: Can't find target for url inset")
1333 target = document.body[j][8:-1]
1334 k = find_token(document.body, "\\end_inset", j)
1336 document.warning("Malformed LyX document: Can't find end of url inset")
1339 newstuff = ["\\begin_inset Flex URL",
1340 "status collapsed", "",
1341 "\\begin_layout Standard",
1346 document.body[i:k] = newstuff
1347 i = i + len(newstuff)
1349 def convert_ams_classes(document):
1350 tc = document.textclass
1351 if (tc != "amsart" and tc != "amsart-plain" and
1352 tc != "amsart-seq" and tc != "amsbook"):
1354 if tc == "amsart-plain":
1355 document.textclass = "amsart"
1356 document.set_textclass()
1357 document.add_module("Theorems (Starred)")
1359 if tc == "amsart-seq":
1360 document.textclass = "amsart"
1361 document.set_textclass()
1362 document.add_module("Theorems (AMS)")
1364 #Now we want to see if any of the environments in the extended theorems
1365 #module were used in this document. If so, we'll add that module, too.
1366 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1367 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1370 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1373 i = find_token(document.body, "\\begin_layout", i)
1376 m = r.match(document.body[i])
1378 # This is an empty layout
1379 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1383 if layouts.count(m) != 0:
1384 document.add_module("Theorems (AMS-Extended)")
1388 def revert_href(document):
1389 'Reverts hyperlink insets (href) to url insets (url)'
1392 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1395 document.body[i : i + 2] = \
1396 ["\\begin_inset CommandInset url", "LatexCommand url"]
1399 def revert_url(document):
1400 'Reverts Flex URL insets to old-style URL insets'
1403 i = find_token(document.body, "\\begin_inset Flex URL", i)
1406 j = find_end_of_inset(document.body, i)
1408 document.warning("Can't find end of inset in revert_url!")
1410 k = find_default_layout(document, i, j)
1412 document.warning("Can't find default layout in revert_url!")
1415 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1416 if l == -1 or l >= j:
1417 document.warning("Can't find end of default layout in revert_url!")
1420 # OK, so the inset's data is between lines k and l.
1421 data = " ".join(document.body[k+1:l])
1423 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1425 document.body[i:j+1] = newinset
1426 i = i + len(newinset)
1429 def convert_include(document):
1430 'Converts include insets to new format.'
1432 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1434 i = find_token(document.body, "\\begin_inset Include", i)
1437 line = document.body[i]
1438 previewline = document.body[i + 1]
1441 document.warning("Unable to match line " + str(i) + " of body!")
1447 insertion = ["\\begin_inset CommandInset include",
1448 "LatexCommand " + cmd, previewline,
1449 "filename \"" + fn + "\""]
1452 insertion.append("lstparams " + '"' + opt + '"')
1454 document.body[i : i + 2] = insertion
1458 def revert_include(document):
1459 'Reverts include insets to old format.'
1461 r0 = re.compile('preview.*')
1462 r1 = re.compile('LatexCommand (.+)')
1463 r2 = re.compile('filename "(.+)"')
1464 r3 = re.compile('lstparams "(.*)"')
1466 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1470 m = r1.match(document.body[nextline])
1472 document.warning("Malformed LyX document: No LatexCommand line for `" +
1473 document.body[i] + "' on line " + str(i) + ".")
1478 if r0.match(document.body[nextline]):
1479 previewline = document.body[nextline]
1483 m = r2.match(document.body[nextline])
1485 document.warning("Malformed LyX document: No filename line for `" + \
1486 document.body[i] + "' on line " + str(i) + ".")
1492 if (cmd == "lstinputlisting"):
1493 m = r3.match(document.body[nextline])
1495 options = m.group(1)
1498 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1500 newline += ("[" + options + "]")
1501 insertion = [newline]
1502 if previewline != "":
1503 insertion.append(previewline)
1504 document.body[i : nextline] = insertion
1508 def revert_albanian(document):
1509 "Set language Albanian to English"
1511 if document.language == "albanian":
1512 document.language = "english"
1513 i = find_token(document.header, "\\language", 0)
1515 document.header[i] = "\\language english"
1518 j = find_token(document.body, "\\lang albanian", j)
1521 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1525 def revert_lowersorbian(document):
1526 "Set language lower Sorbian to English"
1528 if document.language == "lowersorbian":
1529 document.language = "english"
1530 i = find_token(document.header, "\\language", 0)
1532 document.header[i] = "\\language english"
1535 j = find_token(document.body, "\\lang lowersorbian", j)
1538 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1542 def revert_uppersorbian(document):
1543 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1545 if document.language == "uppersorbian":
1546 document.language = "usorbian"
1547 i = find_token(document.header, "\\language", 0)
1549 document.header[i] = "\\language usorbian"
1552 j = find_token(document.body, "\\lang uppersorbian", j)
1555 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1559 def convert_usorbian(document):
1560 "Set language usorbian to uppersorbian"
1562 if document.language == "usorbian":
1563 document.language = "uppersorbian"
1564 i = find_token(document.header, "\\language", 0)
1566 document.header[i] = "\\language uppersorbian"
1569 j = find_token(document.body, "\\lang usorbian", j)
1572 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1576 def convert_macro_global(document):
1577 "Remove TeX code command \global when it is in front of a macro"
1578 # math macros are nowadays already defined \global, so that an additional
1579 # \global would make the document uncompilable, see
1580 # http://bugzilla.lyx.org/show_bug.cgi?id=5371
1581 # We're looking for something like this:
1585 # \begin_layout Plain Layout
1595 # \begin_inset FormulaMacro
1596 # \renewcommand{\foo}{123}
1600 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1603 # if i <= 13, then there isn't enough room for the ERT
1607 if document.body[i-6] == "global":
1608 del document.body[i-13 : i]
1614 def revert_macro_optional_params(document):
1615 "Convert macro definitions with optional parameters into ERTs"
1616 # Stub to convert macro definitions with one or more optional parameters
1617 # into uninterpreted ERT insets
1620 def revert_hyperlinktype(document):
1621 'Reverts hyperlink type'
1625 i = find_token(document.body, "target", i)
1628 j = find_token(document.body, "type", i)
1632 del document.body[j]
1636 def revert_pagebreak(document):
1637 'Reverts pagebreak to ERT'
1640 i = find_token(document.body, "\\pagebreak", i)
1643 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1644 '\\begin_layout Standard\n\n\n\\backslash\n' \
1645 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1649 def revert_linebreak(document):
1650 'Reverts linebreak to ERT'
1653 i = find_token(document.body, "\\linebreak", i)
1656 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1657 '\\begin_layout Standard\n\n\n\\backslash\n' \
1658 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1662 def revert_latin(document):
1663 "Set language Latin to English"
1665 if document.language == "latin":
1666 document.language = "english"
1667 i = find_token(document.header, "\\language", 0)
1669 document.header[i] = "\\language english"
1672 j = find_token(document.body, "\\lang latin", j)
1675 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1679 def revert_samin(document):
1680 "Set language North Sami to English"
1682 if document.language == "samin":
1683 document.language = "english"
1684 i = find_token(document.header, "\\language", 0)
1686 document.header[i] = "\\language english"
1689 j = find_token(document.body, "\\lang samin", j)
1692 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1696 def convert_serbocroatian(document):
1697 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1699 if document.language == "serbocroatian":
1700 document.language = "croatian"
1701 i = find_token(document.header, "\\language", 0)
1703 document.header[i] = "\\language croatian"
1706 j = find_token(document.body, "\\lang serbocroatian", j)
1709 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1713 def convert_framed_notes(document):
1714 "Convert framed notes to boxes. "
1717 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1720 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1729 'height_special "totalheight"']
1730 document.body[i:i+1] = subst
1734 def convert_module_names(document):
1735 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1736 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1737 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1738 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1739 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1740 modlist = document.get_module_list()
1741 if len(modlist) == 0:
1745 if modulemap.has_key(mod):
1746 newmodlist.append(modulemap[mod])
1748 document.warning("Can't find module %s in the module map!" % mod)
1749 newmodlist.append(mod)
1750 document.set_module_list(newmodlist)
1753 def revert_module_names(document):
1754 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1755 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1756 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1757 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1758 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1759 modlist = document.get_module_list()
1760 if len(modlist) == 0:
1764 if modulemap.has_key(mod):
1765 newmodlist.append(modulemap[mod])
1767 document.warning("Can't find module %s in the module map!" % mod)
1768 newmodlist.append(mod)
1769 document.set_module_list(newmodlist)
1772 def revert_colsep(document):
1773 i = find_token(document.header, "\\columnsep", 0)
1776 colsepline = document.header[i]
1777 r = re.compile(r'\\columnsep (.*)')
1778 m = r.match(colsepline)
1780 document.warning("Malformed column separation line!")
1783 del document.header[i]
1784 #it seems to be safe to add the package even if it is already used
1785 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1787 add_to_preamble(document, pretext)
1790 def revert_framed_notes(document):
1791 "Revert framed boxes to notes. "
1794 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1798 j = find_end_of_inset(document.body, i + 1)
1801 document.warning("Malformed LyX document: Could not find end of Box inset.")
1802 k = find_token(document.body, "status", i + 1, j)
1804 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1806 status = document.body[k]
1807 l = find_default_layout(document, i + 1, j)
1809 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1811 m = find_token(document.body, "\\end_layout", i + 1, j)
1813 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1815 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1816 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1817 if ibox == -1 and pbox == -1:
1818 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1819 del document.body[i+1:k]
1821 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1822 subst1 = [document.body[l],
1823 "\\begin_inset Note Shaded",
1825 '\\begin_layout Standard']
1826 document.body[l:l + 1] = subst1
1827 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1828 document.body[m:m + 1] = subst2
1832 def revert_slash(document):
1833 'Revert \\SpecialChar \\slash{} to ERT'
1835 while i < len(document.body):
1836 m = re.match(r'(.*)\\SpecialChar \\slash{}(.*)', document.body[i])
1841 '\\begin_inset ERT',
1842 'status collapsed', '',
1843 '\\begin_layout Standard',
1844 '', '', '\\backslash',
1849 document.body[i: i+1] = subst
1855 def revert_nobreakdash(document):
1856 'Revert \\SpecialChar \\nobreakdash- to ERT'
1858 while i < len(document.body):
1859 m = re.match(r'(.*)\\SpecialChar \\nobreakdash-(.*)', document.body[i])
1864 '\\begin_inset ERT',
1865 'status collapsed', '',
1866 '\\begin_layout Standard', '', '',
1872 document.body[i: i+1] = subst
1874 j = find_token(document.header, "\\use_amsmath", 0)
1876 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1878 document.header[j] = "\\use_amsmath 2"
1883 #Returns number of lines added/removed
1884 def revert_nocite_key(body, start, end):
1885 'key "..." -> \nocite{...}'
1886 r = re.compile(r'^key "(.*)"')
1890 m = r.match(body[i])
1892 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1893 j += 1 # because we added a line
1894 i += 2 # skip that line
1897 j -= 1 # because we deleted a line
1898 # no need to change i, since it now points to the next line
1902 def revert_nocite(document):
1903 "Revert LatexCommand nocite to ERT"
1906 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1909 if (document.body[i+1] != "LatexCommand nocite"):
1910 # note that we already incremented i
1913 insetEnd = find_end_of_inset(document.body, i)
1915 #this should not happen
1916 document.warning("End of CommandInset citation not found in revert_nocite!")
1919 paramLocation = i + 2 #start of the inset's parameters
1921 document.body[i:i+2] = \
1922 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1923 # that added two lines
1926 #print insetEnd, document.body[i: insetEnd + 1]
1927 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1928 #print insetEnd, document.body[i: insetEnd + 1]
1929 document.body.insert(insetEnd, "\\end_layout")
1930 document.body.insert(insetEnd + 1, "")
1934 def revert_btprintall(document):
1935 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1936 i = find_token(document.header, '\\use_bibtopic', 0)
1938 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1940 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1942 while i < len(document.body):
1943 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1946 j = find_end_of_inset(document.body, i + 1)
1948 #this should not happen
1949 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1950 j = len(document.body)
1951 # this range isn't really right, but it should be OK, since we shouldn't
1952 # see more than one matching line in each inset
1954 for k in range(i, j):
1955 if (document.body[k] == 'btprint "btPrintAll"'):
1956 del document.body[k]
1957 subst = ["\\begin_inset ERT",
1958 "status collapsed", "",
1959 "\\begin_layout Standard", "",
1964 document.body[i:i] = subst
1965 addlines = addedlines + len(subst) - 1
1969 def revert_bahasam(document):
1970 "Set language Bahasa Malaysia to Bahasa Indonesia"
1972 if document.language == "bahasam":
1973 document.language = "bahasa"
1974 i = find_token(document.header, "\\language", 0)
1976 document.header[i] = "\\language bahasa"
1979 j = find_token(document.body, "\\lang bahasam", j)
1982 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1986 def revert_interlingua(document):
1987 "Set language Interlingua to English"
1989 if document.language == "interlingua":
1990 document.language = "english"
1991 i = find_token(document.header, "\\language", 0)
1993 document.header[i] = "\\language english"
1996 j = find_token(document.body, "\\lang interlingua", j)
1999 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
2003 def revert_serbianlatin(document):
2004 "Set language Serbian-Latin to Croatian"
2006 if document.language == "serbian-latin":
2007 document.language = "croatian"
2008 i = find_token(document.header, "\\language", 0)
2010 document.header[i] = "\\language croatian"
2013 j = find_token(document.body, "\\lang serbian-latin", j)
2016 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
2020 def revert_rotfloat(document):
2021 " Revert sideways custom floats. "
2024 # whitespace intended (exclude \\begin_inset FloatList)
2025 i = find_token(document.body, "\\begin_inset Float ", i)
2028 line = document.body[i]
2029 r = re.compile(r'\\begin_inset Float (.*)$')
2032 document.warning("Unable to match line " + str(i) + " of body!")
2035 floattype = m.group(1)
2036 if floattype == "figure" or floattype == "table":
2039 j = find_end_of_inset(document.body, i)
2041 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
2045 if get_value(document.body, 'sideways', i, j) == "false":
2048 l = find_default_layout(document, i + 1, j)
2050 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2052 subst = ['\\begin_layout Standard',
2053 '\\begin_inset ERT',
2054 'status collapsed', '',
2055 '\\begin_layout Standard', '', '',
2057 'end{sideways' + floattype + '}',
2058 '\\end_layout', '', '\\end_inset']
2059 document.body[j : j+1] = subst
2060 addedLines = len(subst) - 1
2061 del document.body[i+1 : l]
2062 addedLines -= (l-1) - (i+1)
2063 subst = ['\\begin_inset ERT', 'status collapsed', '',
2064 '\\begin_layout Standard', '', '', '\\backslash',
2065 'begin{sideways' + floattype + '}',
2066 '\\end_layout', '', '\\end_inset', '',
2068 document.body[i : i+1] = subst
2069 addedLines += len(subst) - 1
2070 if floattype == "algorithm":
2071 add_to_preamble(document,
2072 ['% Commands inserted by lyx2lyx for sideways algorithm float',
2073 '\\usepackage{rotfloat}',
2074 '\\floatstyle{ruled}',
2075 '\\newfloat{algorithm}{tbp}{loa}',
2076 '\\floatname{algorithm}{Algorithm}'])
2078 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
2082 def revert_widesideways(document):
2083 " Revert wide sideways floats. "
2086 # whitespace intended (exclude \\begin_inset FloatList)
2087 i = find_token(document.body, '\\begin_inset Float ', i)
2090 line = document.body[i]
2091 r = re.compile(r'\\begin_inset Float (.*)$')
2094 document.warning("Unable to match line " + str(i) + " of body!")
2097 floattype = m.group(1)
2098 if floattype != "figure" and floattype != "table":
2101 j = find_end_of_inset(document.body, i)
2103 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2106 if get_value(document.body, 'sideways', i, j) == "false" or \
2107 get_value(document.body, 'wide', i, j) == "false":
2110 l = find_default_layout(document, i + 1, j)
2112 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2114 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2115 'status collapsed', '',
2116 '\\begin_layout Standard', '', '', '\\backslash',
2117 'end{sideways' + floattype + '*}',
2118 '\\end_layout', '', '\\end_inset']
2119 document.body[j : j+1] = subst
2120 addedLines = len(subst) - 1
2121 del document.body[i+1:l-1]
2122 addedLines -= (l-1) - (i+1)
2123 subst = ['\\begin_inset ERT', 'status collapsed', '',
2124 '\\begin_layout Standard', '', '', '\\backslash',
2125 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2126 '\\end_inset', '', '\\end_layout', '']
2127 document.body[i : i+1] = subst
2128 addedLines += len(subst) - 1
2129 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2133 def revert_inset_embedding(document, type):
2134 ' Remove embed tag from certain type of insets'
2137 i = find_token(document.body, "\\begin_inset %s" % type, i)
2140 j = find_end_of_inset(document.body, i)
2142 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2145 k = find_token(document.body, "\tembed", i, j)
2147 k = find_token(document.body, "embed", i, j)
2149 del document.body[k]
2153 def revert_external_embedding(document):
2154 ' Remove embed tag from external inset '
2155 revert_inset_embedding(document, 'External')
2158 def convert_subfig(document):
2159 " Convert subfigures to subfloats. "
2163 i = find_token(document.body, '\\begin_inset Graphics', i)
2166 endInset = find_end_of_inset(document.body, i)
2168 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2171 k = find_token(document.body, '\tsubcaption', i, endInset)
2175 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2179 caption = document.body[l][16:].strip('"')
2180 del document.body[l]
2182 del document.body[k]
2184 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2185 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2186 '', '\\begin_layout Plain Layout'] + latex2lyx(caption, False) + \
2187 [ '\\end_layout', '', '\\end_inset', '',
2188 '\\end_layout', '', '\\begin_layout Plain Layout']
2189 document.body[i : i] = subst
2190 addedLines += len(subst)
2191 endInset += addedLines
2192 subst = ['', '\\end_inset', '', '\\end_layout']
2193 document.body[endInset : endInset] = subst
2194 addedLines += len(subst)
2198 def revert_subfig(document):
2199 " Revert subfloats. "
2202 # whitespace intended (exclude \\begin_inset FloatList)
2203 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2209 j = find_end_of_inset(document.body, i)
2211 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2212 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2214 continue # this will get us back to the outer loop, since j == -1
2215 # look for embedded float (= subfloat)
2216 # whitespace intended (exclude \\begin_inset FloatList)
2217 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2220 # is the subfloat aligned?
2221 al = find_token(document.body, '\\align ', k - 1, j)
2225 if get_value(document.body, '\\align', al) == "center":
2226 alignment_beg = "\\backslash\nbegin{centering}"
2227 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2228 elif get_value(document.body, '\\align', al) == "left":
2229 alignment_beg = "\\backslash\nbegin{raggedright}"
2230 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2231 elif get_value(document.body, '\\align', al) == "right":
2232 alignment_beg = "\\backslash\nbegin{raggedleft}"
2233 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2234 l = find_end_of_inset(document.body, k)
2236 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2239 continue # escape to the outer loop
2240 m = find_default_layout(document, k + 1, l)
2242 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2247 capend = find_end_of_inset(document.body, cap)
2249 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2253 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2255 lblend = find_end_of_inset(document.body, lbl + 1)
2257 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2259 for line in document.body[lbl:lblend + 1]:
2260 if line.startswith('name '):
2261 label = line.split()[1].strip('"')
2268 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2270 optend = find_end_of_inset(document.body, opt)
2272 document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
2274 optc = find_default_layout(document, opt, optend)
2276 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2278 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2279 for line in document.body[optc:optcend]:
2280 if not line.startswith('\\'):
2281 shortcap += line.strip()
2285 for line in document.body[cap:capend]:
2286 if line in document.body[lbl:lblend]:
2288 elif line in document.body[opt:optend]:
2292 caption += lyxline2latex(document, line, inert)
2294 caption += "\n\\backslash\nlabel{" + label + "}"
2295 subst = '\\begin_layout PlainLayout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2296 '\\begin_layout PlainLayout\n\n}' + alignment_end + \
2297 '\n\\end_layout\n\n\\end_inset\n\n' \
2298 '\\end_layout\n\n\\begin_layout PlainLayout\n'
2299 subst = subst.split('\n')
2300 document.body[l : l+1] = subst
2301 addedLines = len(subst) - 1
2302 # this is before l and so is unchanged by the multiline insertion
2304 del document.body[cap:capend+1]
2305 addedLines -= (capend + 1 - cap)
2306 del document.body[k+1:m-1]
2307 addedLines -= (m - 1 - (k + 1))
2308 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2309 '\\begin_layout PlainLayout\n\n' + alignment_beg + '\n\\backslash\n' \
2311 if len(shortcap) > 0:
2312 insertion = insertion + "[" + shortcap + "]"
2313 if len(caption) > 0:
2314 insertion = insertion + "[" + caption + "]"
2315 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2316 insertion = insertion.split('\n')
2317 document.body[k : k + 1] = insertion
2318 addedLines += len(insertion) - 1
2319 al = find_token(document.body, '\\align ', k - 1, j + addedLines)
2321 del document.body[al]
2323 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2327 def revert_wrapplacement(document):
2328 " Revert placement options wrap floats (wrapfig). "
2331 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2334 e = find_end_of_inset(document.body, i)
2335 j = find_token(document.body, "placement", i + 1, e)
2337 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2340 r = re.compile("placement (o|i|l|r|O|I|L|R)")
2341 m = r.match(document.body[j])
2343 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2345 document.body[j] = "placement " + m.group(1).lower()
2349 def remove_extra_embedded_files(document):
2350 " Remove \extra_embedded_files from buffer params "
2351 i = find_token(document.header, '\\extra_embedded_files', 0)
2354 document.header.pop(i)
2357 def convert_spaceinset(document):
2358 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2360 while i < len(document.body):
2361 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2365 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2366 document.body[i: i+1] = subst
2372 def revert_spaceinset(document):
2373 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2376 i = find_token(document.body, "\\begin_inset Space", i)
2379 j = find_end_of_inset(document.body, i)
2381 document.warning("Malformed LyX document: Could not find end of space inset.")
2383 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2384 del document.body[j]
2387 def convert_hfill(document):
2388 " Convert hfill to space inset "
2391 i = find_token(document.body, "\\hfill", i)
2394 subst = document.body[i].replace('\\hfill', \
2395 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2396 subst = subst.split('\n')
2397 document.body[i : i+1] = subst
2401 def revert_hfills(document):
2402 ' Revert \\hfill commands '
2403 hfill = re.compile(r'\\hfill')
2404 dotfill = re.compile(r'\\dotfill')
2405 hrulefill = re.compile(r'\\hrulefill')
2408 i = find_token(document.body, "\\InsetSpace", i)
2411 if hfill.search(document.body[i]):
2412 document.body[i] = \
2413 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2416 if dotfill.search(document.body[i]):
2417 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2418 '\\begin_inset ERT\nstatus collapsed\n\n' \
2419 '\\begin_layout Standard\n\n\n\\backslash\n' \
2420 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2421 subst = subst.split('\n')
2422 document.body[i : i+1] = subst
2425 if hrulefill.search(document.body[i]):
2426 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2427 '\\begin_inset ERT\nstatus collapsed\n\n' \
2428 '\\begin_layout Standard\n\n\n\\backslash\n' \
2429 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2430 subst = subst.split('\n')
2431 document.body[i : i+1] = subst
2436 def revert_hspace(document):
2437 ' Revert \\InsetSpace \\hspace{} to ERT '
2439 hspace = re.compile(r'\\hspace{}')
2440 hstar = re.compile(r'\\hspace\*{}')
2442 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2445 length = get_value(document.body, '\\length', i+1)
2447 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2449 del document.body[i+1]
2451 if hstar.search(document.body[i]):
2452 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2453 '\\begin_inset ERT\nstatus collapsed\n\n' \
2454 '\\begin_layout Standard\n\n\n\\backslash\n' \
2455 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2456 subst = subst.split('\n')
2457 document.body[i : i+1] = subst
2458 addedLines += len(subst) - 1
2461 if hspace.search(document.body[i]):
2462 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2463 '\\begin_inset ERT\nstatus collapsed\n\n' \
2464 '\\begin_layout Standard\n\n\n\\backslash\n' \
2465 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2466 subst = subst.split('\n')
2467 document.body[i : i+1] = subst
2468 addedLines += len(subst) - 1
2474 def revert_protected_hfill(document):
2475 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2478 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2481 j = find_end_of_inset(document.body, i)
2483 document.warning("Malformed LyX document: Could not find end of space inset.")
2485 del document.body[j]
2486 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2487 '\\begin_inset ERT\nstatus collapsed\n\n' \
2488 '\\begin_layout Standard\n\n\n\\backslash\n' \
2489 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2490 subst = subst.split('\n')
2491 document.body[i : i+1] = subst
2495 def revert_leftarrowfill(document):
2496 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2499 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2502 j = find_end_of_inset(document.body, i)
2504 document.warning("Malformed LyX document: Could not find end of space inset.")
2506 del document.body[j]
2507 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2508 '\\begin_inset ERT\nstatus collapsed\n\n' \
2509 '\\begin_layout Standard\n\n\n\\backslash\n' \
2510 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2511 subst = subst.split('\n')
2512 document.body[i : i+1] = subst
2516 def revert_rightarrowfill(document):
2517 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2520 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2523 j = find_end_of_inset(document.body, i)
2525 document.warning("Malformed LyX document: Could not find end of space inset.")
2527 del document.body[j]
2528 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2529 '\\begin_inset ERT\nstatus collapsed\n\n' \
2530 '\\begin_layout Standard\n\n\n\\backslash\n' \
2531 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2532 subst = subst.split('\n')
2533 document.body[i : i+1] = subst
2537 def revert_upbracefill(document):
2538 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2541 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2544 j = find_end_of_inset(document.body, i)
2546 document.warning("Malformed LyX document: Could not find end of space inset.")
2548 del document.body[j]
2549 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2550 '\\begin_inset ERT\nstatus collapsed\n\n' \
2551 '\\begin_layout Standard\n\n\n\\backslash\n' \
2552 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2553 subst = subst.split('\n')
2554 document.body[i : i+1] = subst
2558 def revert_downbracefill(document):
2559 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2562 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2565 j = find_end_of_inset(document.body, i)
2567 document.warning("Malformed LyX document: Could not find end of space inset.")
2569 del document.body[j]
2570 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2571 '\\begin_inset ERT\nstatus collapsed\n\n' \
2572 '\\begin_layout Standard\n\n\n\\backslash\n' \
2573 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2574 subst = subst.split('\n')
2575 document.body[i : i+1] = subst
2579 def revert_local_layout(document):
2580 ' Revert local layout headers.'
2583 i = find_token(document.header, "\\begin_local_layout", i)
2586 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2588 # this should not happen
2590 document.header[i : j + 1] = []
2593 def convert_pagebreaks(document):
2594 ' Convert inline Newpage insets to new format '
2597 i = find_token(document.body, '\\newpage', i)
2600 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2604 i = find_token(document.body, '\\pagebreak', i)
2607 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2611 i = find_token(document.body, '\\clearpage', i)
2614 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2618 i = find_token(document.body, '\\cleardoublepage', i)
2621 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2625 def revert_pagebreaks(document):
2626 ' Revert \\begin_inset Newpage to previous inline format '
2629 i = find_token(document.body, '\\begin_inset Newpage', i)
2632 j = find_end_of_inset(document.body, i)
2634 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2636 del document.body[j]
2637 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2638 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2639 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2640 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2643 def convert_linebreaks(document):
2644 ' Convert inline Newline insets to new format '
2647 i = find_token(document.body, '\\newline', i)
2650 document.body[i:i+1] = ['\\begin_inset Newline newline',
2654 i = find_token(document.body, '\\linebreak', i)
2657 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2661 def revert_linebreaks(document):
2662 ' Revert \\begin_inset Newline to previous inline format '
2665 i = find_token(document.body, '\\begin_inset Newline', i)
2668 j = find_end_of_inset(document.body, i)
2670 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2672 del document.body[j]
2673 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2674 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2677 def convert_japanese_plain(document):
2678 ' Set language japanese-plain to japanese '
2680 if document.language == "japanese-plain":
2681 document.language = "japanese"
2682 i = find_token(document.header, "\\language", 0)
2684 document.header[i] = "\\language japanese"
2687 j = find_token(document.body, "\\lang japanese-plain", j)
2690 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2694 def revert_pdfpages(document):
2695 ' Revert pdfpages external inset to ERT '
2698 i = find_token(document.body, "\\begin_inset External", i)
2701 j = find_end_of_inset(document.body, i)
2703 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2706 if get_value(document.body, 'template', i, j) == "PDFPages":
2707 filename = get_value(document.body, 'filename', i, j)
2709 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2710 for k in range(i, j):
2711 m = r.match(document.body[k])
2714 angle = get_value(document.body, 'rotateAngle', i, j)
2715 width = get_value(document.body, 'width', i, j)
2716 height = get_value(document.body, 'height', i, j)
2717 scale = get_value(document.body, 'scale', i, j)
2718 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2722 options += ",angle=" + angle
2724 options += "angle=" + angle
2727 options += ",width=" + convert_len(width)
2729 options += "width=" + convert_len(width)
2732 options += ",height=" + convert_len(height)
2734 options += "height=" + convert_len(height)
2737 options += ",scale=" + scale
2739 options += "scale=" + scale
2740 if keepAspectRatio != '':
2742 options += ",keepaspectratio"
2744 options += "keepaspectratio"
2746 options = '[' + options + ']'
2747 del document.body[i+1:j+1]
2748 document.body[i:i+1] = ['\\begin_inset ERT',
2751 '\\begin_layout Standard',
2754 'includepdf' + options + '{' + filename + '}',
2758 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2764 def revert_mexican(document):
2765 ' Set language Spanish(Mexico) to Spanish '
2767 if document.language == "spanish-mexico":
2768 document.language = "spanish"
2769 i = find_token(document.header, "\\language", 0)
2771 document.header[i] = "\\language spanish"
2774 j = find_token(document.body, "\\lang spanish-mexico", j)
2777 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2781 def remove_embedding(document):
2782 ' Remove embed tag from all insets '
2783 revert_inset_embedding(document, 'Graphics')
2784 revert_inset_embedding(document, 'External')
2785 revert_inset_embedding(document, 'CommandInset include')
2786 revert_inset_embedding(document, 'CommandInset bibtex')
2789 def revert_master(document):
2790 ' Remove master param '
2791 i = find_token(document.header, "\\master", 0)
2793 del document.header[i]
2796 def revert_graphics_group(document):
2797 ' Revert group information from graphics insets '
2800 i = find_token(document.body, "\\begin_inset Graphics", i)
2803 j = find_end_of_inset(document.body, i)
2805 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2808 k = find_token(document.body, " groupId", i, j)
2812 del document.body[k]
2816 def update_apa_styles(document):
2817 ' Replace obsolete styles '
2819 if document.textclass != "apa":
2822 obsoletedby = { "Acknowledgments": "Acknowledgements",
2823 "Section*": "Section",
2824 "Subsection*": "Subsection",
2825 "Subsubsection*": "Subsubsection",
2826 "Paragraph*": "Paragraph",
2827 "Subparagraph*": "Subparagraph"}
2830 i = find_token(document.body, "\\begin_layout", i)
2834 layout = document.body[i][14:]
2835 if layout in obsoletedby:
2836 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2841 def convert_paper_sizes(document):
2842 ' exchange size options legalpaper and executivepaper to correct order '
2843 # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2846 i = find_token(document.header, "\\papersize executivepaper", 0)
2848 document.header[i] = "\\papersize legalpaper"
2850 j = find_token(document.header, "\\papersize legalpaper", 0)
2852 document.header[j] = "\\papersize executivepaper"
2855 def revert_paper_sizes(document):
2856 ' exchange size options legalpaper and executivepaper to correct order '
2859 i = find_token(document.header, "\\papersize executivepaper", 0)
2861 document.header[i] = "\\papersize legalpaper"
2863 j = find_token(document.header, "\\papersize legalpaper", 0)
2865 document.header[j] = "\\papersize executivepaper"
2868 def convert_InsetSpace(document):
2869 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2872 i = find_token(document.body, "\\begin_inset Space", i)
2875 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2878 def revert_InsetSpace(document):
2879 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2882 i = find_token(document.body, "\\begin_inset space", i)
2885 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2888 def convert_display_enum(document):
2889 " Convert 'display foo' to 'display false/true'"
2892 i = find_token(document.body, "\tdisplay", i)
2895 val = get_value(document.body, 'display', i)
2897 document.body[i] = document.body[i].replace('none', 'false')
2898 if val == "default":
2899 document.body[i] = document.body[i].replace('default', 'true')
2900 if val == "monochrome":
2901 document.body[i] = document.body[i].replace('monochrome', 'true')
2902 if val == "grayscale":
2903 document.body[i] = document.body[i].replace('grayscale', 'true')
2905 document.body[i] = document.body[i].replace('color', 'true')
2906 if val == "preview":
2907 document.body[i] = document.body[i].replace('preview', 'true')
2911 def revert_display_enum(document):
2912 " Revert 'display false/true' to 'display none/color'"
2915 i = find_token(document.body, "\tdisplay", i)
2918 val = get_value(document.body, 'display', i)
2920 document.body[i] = document.body[i].replace('false', 'none')
2922 document.body[i] = document.body[i].replace('true', 'default')
2926 def remove_fontsCJK(document):
2927 ' Remove font_cjk param '
2928 i = find_token(document.header, "\\font_cjk", 0)
2930 del document.header[i]
2933 def convert_plain_layout(document):
2934 " Convert 'PlainLayout' to 'Plain Layout'"
2937 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2940 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2941 '\\begin_layout Plain Layout')
2945 def revert_plain_layout(document):
2946 " Revert 'Plain Layout' to 'PlainLayout'"
2949 i = find_token(document.body, '\\begin_layout Plain Layout', i)
2952 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2953 '\\begin_layout PlainLayout')
2957 def revert_plainlayout(document):
2958 " Revert 'PlainLayout' to 'Standard'"
2961 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2964 # This will be incorrect for some document classes, since Standard is not always
2965 # the default. But (a) it is probably the best we can do and (b) it will actually
2966 # work, in fact, since an unknown layout will be converted to default.
2967 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2968 '\\begin_layout Standard')
2972 def revert_polytonicgreek(document):
2973 "Set language polytonic Greek to Greek"
2975 if document.language == "polutonikogreek":
2976 document.language = "greek"
2977 i = find_token(document.header, "\\language", 0)
2979 document.header[i] = "\\language greek"
2982 j = find_token(document.body, "\\lang polutonikogreek", j)
2985 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2989 def revert_removed_modules(document):
2992 i = find_token(document.header, "\\begin_remove_modules", i)
2995 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
2997 # this should not happen
2999 document.header[i : j + 1] = []
3002 def add_plain_layout(document):
3005 i = find_token(document.body, "\\begin_layout", i)
3008 if len(document.body[i].split()) == 1:
3009 document.body[i] = "\\begin_layout Plain Layout"
3013 def revert_tabulators(document):
3014 "Revert tabulators to 4 spaces"
3017 i = find_token(document.body, "\t", i)
3020 document.body[i] = document.body[i].replace("\t", " ")
3024 def revert_tabsize(document):
3025 "Revert the tabsize parameter of listings"
3029 # either it is the only parameter
3030 i = find_token(document.body, 'lstparams "tabsize=4"', i)
3032 del document.body[i]
3034 j = find_token(document.body, "lstparams", j)
3037 pos = document.body[j].find(",tabsize=")
3038 document.body[j] = document.body[j][:pos] + '"'
3043 def revert_mongolian(document):
3044 "Set language Mongolian to English"
3046 if document.language == "mongolian":
3047 document.language = "english"
3048 i = find_token(document.header, "\\language", 0)
3050 document.header[i] = "\\language english"
3053 j = find_token(document.body, "\\lang mongolian", j)
3056 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
3060 def revert_default_options(document):
3061 ' Remove param use_default_options '
3062 i = find_token(document.header, "\\use_default_options", 0)
3064 del document.header[i]
3067 def convert_default_options(document):
3068 ' Add param use_default_options and set it to false '
3069 i = find_token(document.header, "\\textclass", 0)
3071 document.warning("Malformed LyX document: Missing `\\textclass'.")
3073 document.header.insert(i, '\\use_default_options false')
3076 def revert_backref_options(document):
3077 ' Revert option pdf_backref=page to pagebackref '
3078 i = find_token(document.header, "\\pdf_backref page", 0)
3080 document.header[i] = "\\pdf_pagebackref true"
3083 def convert_backref_options(document):
3084 ' We have changed the option pagebackref to backref=true '
3085 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3087 document.header[i] = "\\pdf_backref page"
3088 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3090 del document.header[j]
3091 # backref=true was not a valid option, we meant backref=section
3092 k = find_token(document.header, "\\pdf_backref true", 0)
3093 if k != -1 and i != -1:
3094 del document.header[k]
3095 elif k != -1 and j != -1:
3096 document.header[k] = "\\pdf_backref section"
3099 def convert_charstyle_element(document):
3100 "Convert CharStyle to Element for docbook backend"
3101 if document.backend != "docbook":
3105 i = find_token(document.body, "\\begin_inset Flex CharStyle:", i)
3108 document.body[i] = document.body[i].replace('\\begin_inset Flex CharStyle:',
3109 '\\begin_inset Flex Element:')
3111 def revert_charstyle_element(document):
3112 "Convert Element to CharStyle for docbook backend"
3113 if document.backend != "docbook":
3117 i = find_token(document.body, "\\begin_inset Flex Element:", i)
3120 document.body[i] = document.body[i].replace('\\begin_inset Flex Element:',
3121 '\\begin_inset Flex CharStyle:')
3127 supported_versions = ["1.6.0","1.6"]
3128 convert = [[277, [fix_wrong_tables]],
3129 [278, [close_begin_deeper]],
3130 [279, [long_charstyle_names]],
3131 [280, [axe_show_label]],
3134 [283, [convert_flex]],
3138 [287, [convert_wrapfig_options]],
3139 [288, [convert_inset_command]],
3140 [289, [convert_latexcommand_index]],
3143 [292, [convert_japanese_cjk]],
3145 [294, [convert_pdf_options]],
3146 [295, [convert_htmlurl, convert_url]],
3147 [296, [convert_include]],
3148 [297, [convert_usorbian]],
3149 [298, [convert_macro_global]],
3154 [303, [convert_serbocroatian]],
3155 [304, [convert_framed_notes]],
3162 [311, [convert_ams_classes]],
3164 [313, [convert_module_names]],
3167 [316, [convert_subfig]],
3170 [319, [convert_spaceinset, convert_hfill]],
3172 [321, [convert_tablines]],
3173 [322, [convert_plain_layout]],
3174 [323, [convert_pagebreaks]],
3175 [324, [convert_linebreaks]],
3176 [325, [convert_japanese_plain]],
3179 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3182 [331, [convert_ltcaption]],
3184 [333, [update_apa_styles]],
3185 [334, [convert_paper_sizes]],
3186 [335, [convert_InsetSpace]],
3188 [337, [convert_display_enum]],
3191 [340, [add_plain_layout]],
3194 [343, [convert_default_options]],
3195 [344, [convert_backref_options]],
3196 [345, [convert_charstyle_element]]
3199 revert = [[344, [revert_charstyle_element]],
3200 [343, [revert_backref_options]],
3201 [342, [revert_default_options]],
3202 [341, [revert_mongolian]],
3203 [340, [revert_tabulators, revert_tabsize]],
3205 [338, [revert_removed_modules]],
3206 [337, [revert_polytonicgreek]],
3207 [336, [revert_display_enum]],
3208 [335, [remove_fontsCJK]],
3209 [334, [revert_InsetSpace]],
3210 [333, [revert_paper_sizes]],
3212 [331, [revert_graphics_group]],
3213 [330, [revert_ltcaption]],
3214 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
3215 [328, [revert_master]],
3217 [326, [revert_mexican]],
3218 [325, [revert_pdfpages]],
3220 [323, [revert_linebreaks]],
3221 [322, [revert_pagebreaks]],
3222 [321, [revert_local_layout, revert_plain_layout]],
3223 [320, [revert_tablines]],
3224 [319, [revert_protected_hfill]],
3225 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3226 [317, [remove_extra_embedded_files]],
3227 [316, [revert_wrapplacement]],
3228 [315, [revert_subfig]],
3229 [314, [revert_colsep, revert_plainlayout]],
3231 [312, [revert_module_names]],
3232 [311, [revert_rotfloat, revert_widesideways]],
3233 [310, [revert_external_embedding]],
3234 [309, [revert_btprintall]],
3235 [308, [revert_nocite]],
3236 [307, [revert_serbianlatin]],
3237 [306, [revert_slash, revert_nobreakdash]],
3238 [305, [revert_interlingua]],
3239 [304, [revert_bahasam]],
3240 [303, [revert_framed_notes]],
3242 [301, [revert_latin, revert_samin]],
3243 [300, [revert_linebreak]],
3244 [299, [revert_pagebreak]],
3245 [298, [revert_hyperlinktype]],
3246 [297, [revert_macro_optional_params]],
3247 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3248 [295, [revert_include]],
3249 [294, [revert_href, revert_url]],
3250 [293, [revert_pdf_options_2]],
3251 [292, [revert_inset_info]],
3252 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3253 [290, [revert_vietnamese]],
3254 [289, [revert_wraptable]],
3255 [288, [revert_latexcommand_index]],
3256 [287, [revert_inset_command]],
3257 [286, [revert_wrapfig_options]],
3258 [285, [revert_pdf_options]],
3259 [284, [remove_inzip_options]],
3261 [282, [revert_flex]],
3263 [280, [revert_begin_modules]],
3264 [279, [revert_show_label]],
3265 [278, [revert_long_charstyle_names]],
3271 if __name__ == "__main__":