* lyx2lyx/lyx_1_6.py: fix convert_url routine (bug 6121).
[lyx.git] / lib / lyx2lyx / lyx_1_6.py
blob43ea288ca48bd0615fa056781cc8956c85441ef5
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"""
21 import re
22 import unicodedata
23 import sys, os
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")
34 # WARNING!
35 # DO NOT do this:
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
42 # i+= len(subst) - 1
43 # where the last statement resets the counter to accord with the added
44 # lines.
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"
58 return string
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:
65 return
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
75 def convert_len(len):
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]
85 break
87 return len
89 # Return the value of len without the unit in numerical form.
90 def len2value(len):
91 result = re.search('([+-]?[0-9.]+)', len)
92 if result:
93 return float(result.group(1))
94 # No number means 1.0
95 return 1.0
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)
101 if l == -1:
102 l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
103 if l == -1:
104 l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
105 return l
107 def get_option(document, m, option, default):
108 l = document.body[m].find(option)
109 val = default
110 if l != -1:
111 val = document.body[m][l:].split('"')[1]
112 return val
114 def remove_option(document, m, option):
115 l = document.body[m].find(option)
116 if l != -1:
117 val = document.body[m][l:].split('"')[1]
118 document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
119 return l
121 def set_option(document, m, option, value):
122 l = document.body[m].find(option)
123 if l != -1:
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):]
127 else:
128 document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
129 return l
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'))
136 spec_chars = []
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)
147 try:
148 [ucs4,command,dead] = line.split(None,2)
149 if command[0:1] != "\\":
150 continue
151 spec_chars.append([command, unichr(eval(ucs4))])
152 except:
153 continue
154 m = r.match(command)
155 if m != None:
156 command = "\\\\"
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) == "\"":
160 command += "\\"
161 commandbl = command
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))])
166 fp.close()
167 return spec_chars
170 def extract_argument(line):
171 'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
173 if not line:
174 return (None, "")
176 bracere = re.compile("(\s*)(.*)")
177 n = bracere.match(line)
178 whitespace = n.group(1)
179 stuff = n.group(2)
180 brace = stuff[:1]
181 if brace != "[" and brace != "{":
182 return (None, line)
184 # find closing brace
185 remain = stuff[1:]
186 pos = 0
187 num = 1
188 term = "}"
189 if brace == "[":
190 term = "]"
191 skip = False
192 for c in remain:
193 if skip:
194 skip = False
195 elif c == "\\":
196 skip = True
197 elif c == brace:
198 num += 1
199 elif c == term:
200 num -= 1
201 if c == 0:
202 break
203 pos += 1
204 if num != 0:
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
208 return (line, "")
209 return (line[:pos + 1], line[pos + 1:])
212 def latex2ert(line):
213 '''Converts LaTeX commands into ERT. line may well be a multi-line
214 string when it is returned.'''
215 if not line:
216 return line
218 retval = ""
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)
227 while m != None:
228 retval += m.group(1)
229 cmd = m.group(2)
230 end = m.group(3)
232 while True:
233 (arg, rest) = extract_argument(end)
234 if arg == None:
235 break
236 cmd += arg
237 end = rest
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"
244 line = end
245 m = labelre.match(line)
246 # put all remaining braces in ERT
247 line = wrap_into_ert(line, '}', '}')
248 line = wrap_into_ert(line, '{', '{')
249 retval += line
250 return retval
253 unicode_reps = read_unicodesymbols()
255 #Bug 5022....
256 #Might should do latex2ert first, then deal with stuff that DOESN'T
257 #end up inside ERT. That routine could be modified so that it returned
258 #a list of lines, and we could then skip ERT bits and only deal with
259 #the other bits.
260 def latex2lyx(data):
261 '''Takes a string, possibly multi-line, and returns the result of
262 converting LaTeX constructs into LyX constructs. Returns a list of
263 lines, suitable for insertion into document.body.'''
265 if not data:
266 return [""]
267 retval = []
269 # Convert LaTeX to Unicode
270 # Commands of this sort need to be checked to make sure they are
271 # followed by a non-alpha character, lest we replace too much.
272 hardone = re.compile(r'^\\\\[a-zA-Z]+$')
274 for rep in unicode_reps:
275 if hardone.match(rep[0]):
276 pos = 0
277 while True:
278 pos = data.find(rep[0], pos)
279 if pos == -1:
280 break
281 nextpos = pos + len(rep[0])
282 if nextpos < len(data) and data[nextpos].isalpha():
283 # not the end of that command
284 pos = nextpos
285 continue
286 data = data[:pos] + rep[1] + data[nextpos:]
287 pos = nextpos
288 else:
289 data = data.replace(rep[0], rep[1])
291 # Generic
292 # \" -> ":
293 data = wrap_into_ert(data, r'\"', '"')
294 # \\ -> \:
295 data = data.replace('\\\\', '\\')
297 # Math:
298 mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
299 lines = data.split('\n')
300 for line in lines:
301 #document.warning("LINE: " + line)
302 #document.warning(str(i) + ":" + document.body[i])
303 #document.warning("LAST: " + document.body[-1])
304 g = line
305 m = mathre.match(g)
306 while m != None:
307 s = m.group(1)
308 f = m.group(2).replace('\\\\', '\\')
309 g = m.group(3)
310 if s:
311 # this is non-math!
312 s = latex2ert(s)
313 subst = s.split('\n')
314 retval += subst
315 retval.append("\\begin_inset Formula " + f)
316 retval.append("\\end_inset")
317 m = mathre.match(g)
318 # Handle whatever is left, which is just text
319 g = latex2ert(g)
320 subst = g.split('\n')
321 retval += subst
322 return retval
325 def lyxline2latex(document, line, inert):
326 'Convert some LyX stuff into corresponding LaTeX stuff line-wise, as best we can.'
327 if line.startswith("\\begin_inset Formula"):
328 line = line[20:]
329 elif line.startswith("\\begin_inset Quotes"):
330 # For now, we do a very basic reversion. Someone who understands
331 # quotes is welcome to fix it up.
332 qtype = line[20:].strip()
333 # lang = qtype[0]
334 side = qtype[1]
335 dbls = qtype[2]
336 if side == "l":
337 if dbls == "d":
338 line = "``"
339 else:
340 line = "`"
341 else:
342 if dbls == "d":
343 line = "''"
344 else:
345 line = "'"
346 elif line.isspace() or \
347 line.startswith("\\begin_layout") or \
348 line.startswith("\\end_layout") or \
349 line.startswith("\\begin_inset") or \
350 line.startswith("\\end_inset") or \
351 line.startswith("\\lang") or \
352 line.strip() == "status collapsed" or \
353 line.strip() == "status open":
354 #skip all that stuff
355 return ""
357 # this needs to be added to the preamble because of cases like
358 # \textmu, \textbackslash, etc.
359 add_to_preamble(document, ['% added by lyx2lyx for converted entries',
360 '\\@ifundefined{textmu}',
361 ' {\\usepackage{textcomp}}{}'])
362 # a lossless reversion is not possible
363 # try at least to handle some common insets and settings
364 if inert:
365 line = line.replace(r'\backslash', '\\')
366 else:
367 line = line.replace('&', '\\&{}')
368 line = line.replace('#', '\\#{}')
369 line = line.replace('^', '\\^{}')
370 line = line.replace('%', '\\%{}')
371 line = line.replace('_', '\\_{}')
372 line = line.replace('$', '\\${}')
374 # Do the LyX text --> LaTeX conversion
375 for rep in unicode_reps:
376 line = line.replace(rep[1], rep[0].replace('\\\\', '\\') + "{}")
377 line = line.replace(r'\backslash', r'\textbackslash{}')
378 line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
379 line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
380 line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
381 line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
382 line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
383 line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
384 line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
385 line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
386 line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
387 return line
390 def lyx2latex(document, lines):
391 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
392 # clean up multiline stuff
393 content = ""
394 ert_end = 0
396 for curline in range(len(lines)):
397 line = lines[curline]
398 if line.startswith("\\begin_inset ERT"):
399 # We don't want to replace things inside ERT, so figure out
400 # where the end of the inset is.
401 ert_end = find_end_of_inset(lines, curline + 1)
402 continue
403 inert = ert_end >= curline
404 content += lyxline2latex(document, lines[curline], inert)
406 return content
409 ####################################################################
411 def convert_ltcaption(document):
412 i = 0
413 while True:
414 i = find_token(document.body, "\\begin_inset Tabular", i)
415 if i == -1:
416 return
417 j = find_end_of_inset(document.body, i + 1)
418 if j == -1:
419 document.warning("Malformed LyX document: Could not find end of tabular.")
420 continue
422 nrows = int(document.body[i+1].split('"')[3])
423 ncols = int(document.body[i+1].split('"')[5])
425 m = i + 1
426 for k in range(nrows):
427 m = find_token(document.body, "<row", m)
428 r = m
429 caption = 'false'
430 for k in range(ncols):
431 m = find_token(document.body, "<cell", m)
432 if (k == 0):
433 mend = find_token(document.body, "</cell>", m + 1)
434 # first look for caption insets
435 mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
436 # then look for ERT captions
437 if mcap == -1:
438 mcap = find_token(document.body, "caption", m + 1, mend)
439 if mcap > -1:
440 mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
441 if mcap > -1:
442 caption = 'true'
443 if caption == 'true':
444 if (k == 0):
445 set_option(document, r, 'caption', 'true')
446 set_option(document, m, 'multicolumn', '1')
447 set_option(document, m, 'bottomline', 'false')
448 set_option(document, m, 'topline', 'false')
449 set_option(document, m, 'rightline', 'false')
450 set_option(document, m, 'leftline', 'false')
451 #j = find_end_of_inset(document.body, j + 1)
452 else:
453 set_option(document, m, 'multicolumn', '2')
454 m = m + 1
455 m = m + 1
457 i = j + 1
460 #FIXME Use of wrap_into_ert can confuse lyx2lyx
461 def revert_ltcaption(document):
462 i = 0
463 while True:
464 i = find_token(document.body, "\\begin_inset Tabular", i)
465 if i == -1:
466 return
467 j = find_end_of_inset(document.body, i + 1)
468 if j == -1:
469 document.warning("Malformed LyX document: Could not find end of tabular.")
470 continue
472 m = i + 1
473 nrows = int(document.body[i+1].split('"')[3])
474 ncols = int(document.body[i+1].split('"')[5])
476 for k in range(nrows):
477 m = find_token(document.body, "<row", m)
478 caption = get_option(document, m, 'caption', 'false')
479 if caption == 'true':
480 remove_option(document, m, 'caption')
481 for k in range(ncols):
482 m = find_token(document.body, "<cell", m)
483 remove_option(document, m, 'multicolumn')
484 if k == 0:
485 m = find_token(document.body, "\\begin_inset Caption", m)
486 if m == -1:
487 return
488 m = find_end_of_inset(document.body, m + 1)
489 document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
490 m = m + 1
491 m = m + 1
492 i = j + 1
495 def convert_tablines(document):
496 i = 0
497 while True:
498 i = find_token(document.body, "\\begin_inset Tabular", i)
499 if i == -1:
500 # LyX 1.3 inserted an extra space between \begin_inset
501 # and Tabular so let us try if this is the case and fix it.
502 i = find_token(document.body, "\\begin_inset Tabular", i)
503 if i == -1:
504 return
505 else:
506 document.body[i] = "\\begin_inset Tabular"
507 j = find_end_of_inset(document.body, i + 1)
508 if j == -1:
509 document.warning("Malformed LyX document: Could not find end of tabular.")
510 continue
512 m = i + 1
513 nrows = int(document.body[i+1].split('"')[3])
514 ncols = int(document.body[i+1].split('"')[5])
516 col_info = []
517 for k in range(ncols):
518 m = find_token(document.body, "<column", m)
519 left = get_option(document, m, 'leftline', 'false')
520 right = get_option(document, m, 'rightline', 'false')
521 col_info.append([left, right])
522 remove_option(document, m, 'leftline')
523 remove_option(document, m, 'rightline')
524 m = m + 1
526 row_info = []
527 for k in range(nrows):
528 m = find_token(document.body, "<row", m)
529 top = get_option(document, m, 'topline', 'false')
530 bottom = get_option(document, m, 'bottomline', 'false')
531 row_info.append([top, bottom])
532 remove_option(document, m, 'topline')
533 remove_option(document, m, 'bottomline')
534 m = m + 1
536 m = i + 1
537 mc_info = []
538 for k in range(nrows*ncols):
539 m = find_token(document.body, "<cell", m)
540 mc_info.append(get_option(document, m, 'multicolumn', '0'))
541 m = m + 1
542 m = i + 1
543 for l in range(nrows):
544 for k in range(ncols):
545 m = find_token(document.body, '<cell', m)
546 if mc_info[l*ncols + k] == '0':
547 r = set_option(document, m, 'topline', row_info[l][0])
548 r = set_option(document, m, 'bottomline', row_info[l][1])
549 r = set_option(document, m, 'leftline', col_info[k][0])
550 r = set_option(document, m, 'rightline', col_info[k][1])
551 elif mc_info[l*ncols + k] == '1':
552 s = k + 1
553 while s < ncols and mc_info[l*ncols + s] == '2':
554 s = s + 1
555 if s < ncols and mc_info[l*ncols + s] != '1':
556 r = set_option(document, m, 'rightline', col_info[k][1])
557 if k > 0 and mc_info[l*ncols + k - 1] == '0':
558 r = set_option(document, m, 'leftline', col_info[k][0])
559 m = m + 1
560 i = j + 1
563 def revert_tablines(document):
564 i = 0
565 while True:
566 i = find_token(document.body, "\\begin_inset Tabular", i)
567 if i == -1:
568 return
569 j = find_end_of_inset(document.body, i + 1)
570 if j == -1:
571 document.warning("Malformed LyX document: Could not find end of tabular.")
572 continue
574 m = i + 1
575 nrows = int(document.body[i+1].split('"')[3])
576 ncols = int(document.body[i+1].split('"')[5])
578 lines = []
579 for k in range(nrows*ncols):
580 m = find_token(document.body, "<cell", m)
581 top = get_option(document, m, 'topline', 'false')
582 bottom = get_option(document, m, 'bottomline', 'false')
583 left = get_option(document, m, 'leftline', 'false')
584 right = get_option(document, m, 'rightline', 'false')
585 lines.append([top, bottom, left, right])
586 m = m + 1
588 # we will want to ignore longtable captions
589 m = i + 1
590 caption_info = []
591 for k in range(nrows):
592 m = find_token(document.body, "<row", m)
593 caption = get_option(document, m, 'caption', 'false')
594 caption_info.append([caption])
595 m = m + 1
597 m = i + 1
598 col_info = []
599 for k in range(ncols):
600 m = find_token(document.body, "<column", m)
601 left = 'true'
602 for l in range(nrows):
603 left = lines[l*ncols + k][2]
604 if left == 'false' and caption_info[l] == 'false':
605 break
606 set_option(document, m, 'leftline', left)
607 right = 'true'
608 for l in range(nrows):
609 right = lines[l*ncols + k][3]
610 if right == 'false' and caption_info[l] == 'false':
611 break
612 set_option(document, m, 'rightline', right)
613 m = m + 1
615 row_info = []
616 for k in range(nrows):
617 m = find_token(document.body, "<row", m)
618 top = 'true'
619 for l in range(ncols):
620 top = lines[k*ncols + l][0]
621 if top == 'false':
622 break
623 if caption_info[k] == 'false':
624 top = 'false'
625 set_option(document, m, 'topline', top)
626 bottom = 'true'
627 for l in range(ncols):
628 bottom = lines[k*ncols + l][1]
629 if bottom == 'false':
630 break
631 if caption_info[k] == 'false':
632 bottom = 'false'
633 set_option(document, m, 'bottomline', bottom)
634 m = m + 1
636 i = j + 1
639 def fix_wrong_tables(document):
640 i = 0
641 while True:
642 i = find_token(document.body, "\\begin_inset Tabular", i)
643 if i == -1:
644 return
645 j = find_end_of_inset(document.body, i + 1)
646 if j == -1:
647 document.warning("Malformed LyX document: Could not find end of tabular.")
648 continue
650 m = i + 1
651 nrows = int(document.body[i+1].split('"')[3])
652 ncols = int(document.body[i+1].split('"')[5])
654 for l in range(nrows):
655 prev_multicolumn = 0
656 for k in range(ncols):
657 m = find_token(document.body, '<cell', m)
659 if document.body[m].find('multicolumn') != -1:
660 multicol_cont = int(document.body[m].split('"')[1])
662 if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
663 document.body[m] = document.body[m][:5] + document.body[m][21:]
664 prev_multicolumn = 0
665 else:
666 prev_multicolumn = multicol_cont
667 else:
668 prev_multicolumn = 0
670 i = j + 1
673 def close_begin_deeper(document):
674 i = 0
675 depth = 0
676 while True:
677 i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
679 if i == -1:
680 break
682 if document.body[i][:13] == "\\begin_deeper":
683 depth += 1
684 else:
685 depth -= 1
687 i += 1
689 document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
692 def long_charstyle_names(document):
693 i = 0
694 while True:
695 i = find_token(document.body, "\\begin_inset CharStyle", i)
696 if i == -1:
697 return
698 document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
699 i += 1
701 def revert_long_charstyle_names(document):
702 i = 0
703 while True:
704 i = find_token(document.body, "\\begin_inset CharStyle", i)
705 if i == -1:
706 return
707 document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
708 i += 1
711 def axe_show_label(document):
712 i = 0
713 while True:
714 i = find_token(document.body, "\\begin_inset CharStyle", i)
715 if i == -1:
716 return
717 if document.body[i + 1].find("show_label") != -1:
718 if document.body[i + 1].find("true") != -1:
719 document.body[i + 1] = "status open"
720 del document.body[ i + 2]
721 else:
722 if document.body[i + 1].find("false") != -1:
723 document.body[i + 1] = "status collapsed"
724 del document.body[ i + 2]
725 else:
726 document.warning("Malformed LyX document: show_label neither false nor true.")
727 else:
728 document.warning("Malformed LyX document: show_label missing in CharStyle.")
730 i += 1
733 def revert_show_label(document):
734 i = 0
735 while True:
736 i = find_token(document.body, "\\begin_inset CharStyle", i)
737 if i == -1:
738 return
739 if document.body[i + 1].find("status open") != -1:
740 document.body.insert(i + 1, "show_label true")
741 else:
742 if document.body[i + 1].find("status collapsed") != -1:
743 document.body.insert(i + 1, "show_label false")
744 else:
745 document.warning("Malformed LyX document: no legal status line in CharStyle.")
746 i += 1
748 def revert_begin_modules(document):
749 i = 0
750 while True:
751 i = find_token(document.header, "\\begin_modules", i)
752 if i == -1:
753 return
754 j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
755 if j == -1:
756 # this should not happen
757 break
758 document.header[i : j + 1] = []
760 def convert_flex(document):
761 "Convert CharStyle to Flex"
762 i = 0
763 while True:
764 i = find_token(document.body, "\\begin_inset CharStyle", i)
765 if i == -1:
766 return
767 document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
769 def revert_flex(document):
770 "Convert Flex to CharStyle"
771 i = 0
772 while True:
773 i = find_token(document.body, "\\begin_inset Flex", i)
774 if i == -1:
775 return
776 document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
779 def revert_pdf_options(document):
780 "Revert PDF options for hyperref."
781 # store the PDF options and delete the entries from the Lyx file
782 i = 0
783 hyperref = False
784 title = ""
785 author = ""
786 subject = ""
787 keywords = ""
788 bookmarks = ""
789 bookmarksnumbered = ""
790 bookmarksopen = ""
791 bookmarksopenlevel = ""
792 breaklinks = ""
793 pdfborder = ""
794 colorlinks = ""
795 backref = ""
796 pagebackref = ""
797 pagemode = ""
798 otheroptions = ""
799 i = find_token(document.header, "\\use_hyperref", i)
800 if i != -1:
801 hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
802 del document.header[i]
803 i = find_token(document.header, "\\pdf_store_options", i)
804 if i != -1:
805 del document.header[i]
806 i = find_token(document.header, "\\pdf_title", 0)
807 if i != -1:
808 title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
809 title = ' pdftitle={' + title + '}'
810 del document.header[i]
811 i = find_token(document.header, "\\pdf_author", 0)
812 if i != -1:
813 author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
814 if title == "":
815 author = ' pdfauthor={' + author + '}'
816 else:
817 author = ',\n pdfauthor={' + author + '}'
818 del document.header[i]
819 i = find_token(document.header, "\\pdf_subject", 0)
820 if i != -1:
821 subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
822 if title == "" and author == "":
823 subject = ' pdfsubject={' + subject + '}'
824 else:
825 subject = ',\n pdfsubject={' + subject + '}'
826 del document.header[i]
827 i = find_token(document.header, "\\pdf_keywords", 0)
828 if i != -1:
829 keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
830 if title == "" and author == "" and subject == "":
831 keywords = ' pdfkeywords={' + keywords + '}'
832 else:
833 keywords = ',\n pdfkeywords={' + keywords + '}'
834 del document.header[i]
835 i = find_token(document.header, "\\pdf_bookmarks", 0)
836 if i != -1:
837 bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
838 bookmarks = ',\n bookmarks=' + bookmarks
839 del document.header[i]
840 i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
841 if i != -1:
842 bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
843 bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
844 del document.header[i]
845 i = find_token(document.header, "\\pdf_bookmarksopen", i)
846 if i != -1:
847 bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
848 bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
849 del document.header[i]
850 i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
851 if i != -1:
852 bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
853 bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
854 del document.header[i]
855 i = find_token(document.header, "\\pdf_breaklinks", i)
856 if i != -1:
857 breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
858 breaklinks = ',\n breaklinks=' + breaklinks
859 del document.header[i]
860 i = find_token(document.header, "\\pdf_pdfborder", i)
861 if i != -1:
862 pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
863 if pdfborder == 'true':
864 pdfborder = ',\n pdfborder={0 0 0}'
865 else:
866 pdfborder = ',\n pdfborder={0 0 1}'
867 del document.header[i]
868 i = find_token(document.header, "\\pdf_colorlinks", i)
869 if i != -1:
870 colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
871 colorlinks = ',\n colorlinks=' + colorlinks
872 del document.header[i]
873 i = find_token(document.header, "\\pdf_backref", i)
874 if i != -1:
875 backref = get_value_string(document.header, '\\pdf_backref', 0)
876 backref = ',\n backref=' + backref
877 del document.header[i]
878 i = find_token(document.header, "\\pdf_pagebackref", i)
879 if i != -1:
880 pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
881 pagebackref = ',\n pagebackref=' + pagebackref
882 del document.header[i]
883 i = find_token(document.header, "\\pdf_pagemode", 0)
884 if i != -1:
885 pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
886 pagemode = ',\n pdfpagemode=' + pagemode
887 del document.header[i]
888 i = find_token(document.header, "\\pdf_quoted_options", 0)
889 if i != -1:
890 otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
891 if title == "" and author == "" and subject == "" and keywords == "":
892 otheroptions = ' ' + otheroptions
893 else:
894 otheroptions = ',\n ' + otheroptions
895 del document.header[i]
897 # write to the preamble when hyperref was used
898 if hyperref == True:
899 # preamble write preparations
900 # bookmark numbers are only output when they are turned on
901 if bookmarksopen == ',\n bookmarksopen=true':
902 bookmarksopen = bookmarksopen + bookmarksopenlevel
903 if bookmarks == ',\n bookmarks=true':
904 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
905 else:
906 bookmarks = bookmarks
907 # hypersetup is only output when there are things to be set up
908 setupstart = '\\hypersetup{%\n'
909 setupend = ' }\n'
910 if otheroptions == "" and title == "" and author == ""\
911 and subject == "" and keywords == "":
912 setupstart = ""
913 setupend = ""
914 # write the preamble
915 # babel must be loaded before hyperref and hyperref the first part
916 # of the preamble, like in LyX 1.6
917 insert_to_preamble(0, document,
918 '% Commands inserted by lyx2lyx for PDF properties\n'
919 + '\\usepackage{babel}\n'
920 + '\\usepackage[unicode=true'
921 + bookmarks
922 + breaklinks
923 + pdfborder
924 + backref
925 + pagebackref
926 + colorlinks
927 + pagemode
928 + ']\n'
929 + ' {hyperref}\n'
930 + setupstart
931 + title
932 + author
933 + subject
934 + keywords
935 + otheroptions
936 + setupend)
939 def remove_inzip_options(document):
940 "Remove inzipName and embed options from the Graphics inset"
941 i = 0
942 while 1:
943 i = find_token(document.body, "\\begin_inset Graphics", i)
944 if i == -1:
945 return
946 j = find_end_of_inset(document.body, i + 1)
947 if j == -1:
948 # should not happen
949 document.warning("Malformed LyX document: Could not find end of graphics inset.")
950 # If there's a inzip param, just remove that
951 k = find_token(document.body, "\tinzipName", i + 1, j)
952 if k != -1:
953 del document.body[k]
954 # embed option must follow the inzipName option
955 del document.body[k+1]
956 i = i + 1
959 def convert_inset_command(document):
961 Convert:
962 \begin_inset LatexCommand cmd
964 \begin_inset CommandInset InsetType
965 LatexCommand cmd
967 i = 0
968 while 1:
969 i = find_token(document.body, "\\begin_inset LatexCommand", i)
970 if i == -1:
971 return
972 line = document.body[i]
973 r = re.compile(r'\\begin_inset LatexCommand (.*)$')
974 m = r.match(line)
975 cmdName = m.group(1)
976 insetName = ""
977 #this is adapted from factory.cpp
978 if cmdName[0:4].lower() == "cite":
979 insetName = "citation"
980 elif cmdName == "url" or cmdName == "htmlurl":
981 insetName = "url"
982 elif cmdName[-3:] == "ref":
983 insetName = "ref"
984 elif cmdName == "tableofcontents":
985 insetName = "toc"
986 elif cmdName == "printnomenclature":
987 insetName = "nomencl_print"
988 elif cmdName == "printindex":
989 insetName = "index_print"
990 else:
991 insetName = cmdName
992 insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
993 document.body[i : i+1] = insertion
996 def revert_inset_command(document):
998 Convert:
999 \begin_inset CommandInset InsetType
1000 LatexCommand cmd
1002 \begin_inset LatexCommand cmd
1003 Some insets may end up being converted to insets earlier versions of LyX
1004 will not be able to recognize. Not sure what to do about that.
1006 i = 0
1007 while 1:
1008 i = find_token(document.body, "\\begin_inset CommandInset", i)
1009 if i == -1:
1010 return
1011 nextline = document.body[i+1]
1012 r = re.compile(r'LatexCommand\s+(.*)$')
1013 m = r.match(nextline)
1014 if not m:
1015 document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
1016 i += 1
1017 continue
1018 cmdName = m.group(1)
1019 insertion = ["\\begin_inset LatexCommand " + cmdName]
1020 document.body[i : i+2] = insertion
1023 def convert_wrapfig_options(document):
1024 "Convert optional options for wrap floats (wrapfig)."
1025 # adds the tokens "lines", "placement", and "overhang"
1026 i = 0
1027 while True:
1028 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1029 if i == -1:
1030 return
1031 document.body.insert(i + 1, "lines 0")
1032 j = find_token(document.body, "placement", i)
1033 # placement can be already set or not; if not, set it
1034 if j == i+2:
1035 document.body.insert(i + 3, "overhang 0col%")
1036 else:
1037 document.body.insert(i + 2, "placement o")
1038 document.body.insert(i + 3, "overhang 0col%")
1039 i = i + 1
1042 def revert_wrapfig_options(document):
1043 "Revert optional options for wrap floats (wrapfig)."
1044 i = 0
1045 while True:
1046 i = find_token(document.body, "\\begin_inset Wrap figure", i)
1047 if i == -1:
1048 return
1049 j = find_end_of_inset(document.body, i)
1050 if j == -1:
1051 document.warning("Can't find end of Wrap inset at line " + str(i))
1052 i += 1
1053 continue
1054 k = find_default_layout(document, i, j)
1055 if k == -1:
1056 document.warning("Can't find default layout for Wrap figure!")
1057 i = j
1058 continue
1059 # Options should be between i and k now
1060 l = find_token(document.body, "lines", i, k)
1061 if l == -1:
1062 document.warning("Can't find lines option for Wrap figure!")
1063 i = k
1064 continue
1065 m = find_token(document.body, "overhang", i + 1, k)
1066 if m == -1:
1067 document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1068 i = k
1069 continue
1070 # Do these in reverse order
1071 del document.body[m]
1072 del document.body[l]
1073 i = k
1076 def convert_latexcommand_index(document):
1077 "Convert from LatexCommand form to collapsable form."
1078 i = 0
1079 r1 = re.compile('name "(.*)"')
1080 while True:
1081 i = find_token(document.body, "\\begin_inset CommandInset index", i)
1082 if i == -1:
1083 return
1084 if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1085 i += 1
1086 continue
1087 j = find_end_of_inset(document.body, i + 1)
1088 if j == -1:
1089 document.warning("Unable to find end of index inset at line " + str(i) + "!")
1090 i += 2
1091 continue
1092 m = r1.match(document.body[i + 2])
1093 if m == None:
1094 document.warning("Unable to match: " + document.body[i+2])
1095 # this can happen with empty index insets!
1096 linelist = [""]
1097 else:
1098 fullcontent = m.group(1)
1099 linelist = latex2lyx(fullcontent)
1100 #document.warning(fullcontent)
1102 linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \
1103 linelist + ["\\end_layout"]
1104 document.body[i : j] = linelist
1105 i += len(linelist) - (j - i)
1108 def revert_latexcommand_index(document):
1109 "Revert from collapsable form to LatexCommand form."
1110 i = 0
1111 while True:
1112 i = find_token(document.body, "\\begin_inset Index", i)
1113 if i == -1:
1114 return
1115 j = find_end_of_inset(document.body, i + 1)
1116 if j == -1:
1117 return
1119 content = lyx2latex(document, document.body[i:j])
1120 # escape quotes
1121 content = content.replace('"', r'\"')
1122 document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1123 "name " + '"' + content + '"', ""]
1124 i += 5
1127 def revert_wraptable(document):
1128 "Revert wrap table to wrap figure."
1129 i = 0
1130 while True:
1131 i = find_token(document.body, "\\begin_inset Wrap table", i)
1132 if i == -1:
1133 return
1134 document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1135 i = i + 1
1138 def revert_vietnamese(document):
1139 "Set language Vietnamese to English"
1140 # Set document language from Vietnamese to English
1141 i = 0
1142 if document.language == "vietnamese":
1143 document.language = "english"
1144 i = find_token(document.header, "\\language", 0)
1145 if i != -1:
1146 document.header[i] = "\\language english"
1147 j = 0
1148 while True:
1149 j = find_token(document.body, "\\lang vietnamese", j)
1150 if j == -1:
1151 return
1152 document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1153 j = j + 1
1156 def convert_japanese_cjk(document):
1157 "Set language japanese to japanese-cjk"
1158 # Set document language from japanese-plain to japanese
1159 i = 0
1160 if document.language == "japanese":
1161 document.language = "japanese-cjk"
1162 i = find_token(document.header, "\\language", 0)
1163 if i != -1:
1164 document.header[i] = "\\language japanese-cjk"
1165 j = 0
1166 while True:
1167 j = find_token(document.body, "\\lang japanese", j)
1168 if j == -1:
1169 return
1170 document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1171 j = j + 1
1174 def revert_japanese(document):
1175 "Set language japanese-plain to japanese"
1176 # Set document language from japanese-plain to japanese
1177 i = 0
1178 if document.language == "japanese-plain":
1179 document.language = "japanese"
1180 i = find_token(document.header, "\\language", 0)
1181 if i != -1:
1182 document.header[i] = "\\language japanese"
1183 j = 0
1184 while True:
1185 j = find_token(document.body, "\\lang japanese-plain", j)
1186 if j == -1:
1187 return
1188 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1189 j = j + 1
1192 def revert_japanese_cjk(document):
1193 "Set language japanese-cjk to japanese"
1194 # Set document language from japanese-plain to japanese
1195 i = 0
1196 if document.language == "japanese-cjk":
1197 document.language = "japanese"
1198 i = find_token(document.header, "\\language", 0)
1199 if i != -1:
1200 document.header[i] = "\\language japanese"
1201 j = 0
1202 while True:
1203 j = find_token(document.body, "\\lang japanese-cjk", j)
1204 if j == -1:
1205 return
1206 document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1207 j = j + 1
1210 def revert_japanese_encoding(document):
1211 "Set input encoding form EUC-JP-plain to EUC-JP etc."
1212 # Set input encoding form EUC-JP-plain to EUC-JP etc.
1213 i = 0
1214 i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1215 if i != -1:
1216 document.header[i] = "\\inputencoding EUC-JP"
1217 j = 0
1218 j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1219 if j != -1:
1220 document.header[j] = "\\inputencoding JIS"
1221 k = 0
1222 k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1223 if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1224 document.header[k] = "\\inputencoding UTF8"
1227 def revert_inset_info(document):
1228 'Replace info inset with its content'
1229 i = 0
1230 while 1:
1231 i = find_token(document.body, '\\begin_inset Info', i)
1232 if i == -1:
1233 return
1234 j = find_end_of_inset(document.body, i + 1)
1235 if j == -1:
1236 # should not happen
1237 document.warning("Malformed LyX document: Could not find end of Info inset.")
1238 type = 'unknown'
1239 arg = ''
1240 for k in range(i, j+1):
1241 if document.body[k].startswith("arg"):
1242 arg = document.body[k][3:].strip()
1243 # remove embracing quotation marks
1244 if arg[0] == '"':
1245 arg = arg[1:]
1246 if arg[len(arg) - 1] == '"':
1247 arg = arg[:len(arg) - 1]
1248 # \" to straight quote
1249 arg = arg.replace(r'\"', '"')
1250 # \ to \backslash
1251 arg = arg.replace(r'\\', "\\backslash\n")
1252 if document.body[k].startswith("type"):
1253 type = document.body[k][4:].strip().strip('"')
1254 # I think there is a newline after \\end_inset, which should be removed.
1255 if document.body[j + 1].strip() == "":
1256 document.body[i : (j + 2)] = [type + ':' + arg]
1257 else:
1258 document.body[i : (j + 1)] = [type + ':' + arg]
1261 def convert_pdf_options(document):
1262 # Set the pdfusetitle tag, delete the pdf_store_options,
1263 # set quotes for bookmarksopenlevel"
1264 has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1265 if has_hr == "1":
1266 k = find_token(document.header, "\\use_hyperref", 0)
1267 document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1268 k = find_token(document.header, "\\pdf_store_options", 0)
1269 if k != -1:
1270 del document.header[k]
1271 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1272 if i == -1: return
1273 document.header[i] = document.header[i].replace('"', '')
1276 def revert_pdf_options_2(document):
1277 # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1278 k = find_token(document.header, "\\use_hyperref", 0)
1279 i = find_token(document.header, "\\pdf_pdfusetitle", k)
1280 if i != -1:
1281 del document.header[i]
1282 i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1283 if i == -1: return
1284 values = document.header[i].split()
1285 values[1] = ' "' + values[1] + '"'
1286 document.header[i] = ''.join(values)
1289 def convert_htmlurl(document):
1290 'Convert "htmlurl" to "href" insets for docbook'
1291 if document.backend != "docbook":
1292 return
1293 i = 0
1294 while True:
1295 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1296 if i == -1:
1297 return
1298 document.body[i] = "\\begin_inset CommandInset href"
1299 document.body[i + 1] = "LatexCommand href"
1300 i = i + 1
1303 def convert_url(document):
1304 'Convert url insets to url charstyles'
1305 if document.backend == "docbook":
1306 return
1307 i = 0
1308 while True:
1309 i = find_token(document.body, "\\begin_inset CommandInset url", i)
1310 if i == -1:
1311 break
1312 n = find_token(document.body, "name", i)
1313 if n == i + 2:
1314 # place the URL name in typewriter before the new URL insert
1315 # grab the name 'bla' from the e.g. the line 'name "bla"',
1316 # therefore start with the 6th character
1317 name = document.body[n][6:-1]
1318 newname = [name + " "]
1319 document.body[i:i] = newname
1320 i = i + 1
1321 j = find_token(document.body, "target", i)
1322 if j == -1:
1323 document.warning("Malformed LyX document: Can't find target for url inset")
1324 i += 1
1325 continue
1326 target = document.body[j][8:-1]
1327 k = find_token(document.body, "\\end_inset", j)
1328 if k == -1:
1329 document.warning("Malformed LyX document: Can't find end of url inset")
1330 i = j
1331 continue
1332 newstuff = ["\\begin_inset Flex URL",
1333 "status collapsed", "",
1334 "\\begin_layout Standard",
1336 target,
1337 "\\end_layout",
1339 document.body[i:k] = newstuff
1340 i = i + len(newstuff)
1342 def convert_ams_classes(document):
1343 tc = document.textclass
1344 if (tc != "amsart" and tc != "amsart-plain" and
1345 tc != "amsart-seq" and tc != "amsbook"):
1346 return
1347 if tc == "amsart-plain":
1348 document.textclass = "amsart"
1349 document.set_textclass()
1350 document.add_module("Theorems (Starred)")
1351 return
1352 if tc == "amsart-seq":
1353 document.textclass = "amsart"
1354 document.set_textclass()
1355 document.add_module("Theorems (AMS)")
1357 #Now we want to see if any of the environments in the extended theorems
1358 #module were used in this document. If so, we'll add that module, too.
1359 layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note", \
1360 "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1361 "Assumption"]
1363 r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1364 i = 0
1365 while True:
1366 i = find_token(document.body, "\\begin_layout", i)
1367 if i == -1:
1368 return
1369 m = r.match(document.body[i])
1370 if m == None:
1371 # This is an empty layout
1372 # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1373 i += 1
1374 continue
1375 m = m.group(1)
1376 if layouts.count(m) != 0:
1377 document.add_module("Theorems (AMS-Extended)")
1378 return
1379 i += 1
1381 def revert_href(document):
1382 'Reverts hyperlink insets (href) to url insets (url)'
1383 i = 0
1384 while True:
1385 i = find_token(document.body, "\\begin_inset CommandInset href", i)
1386 if i == -1:
1387 return
1388 document.body[i : i + 2] = \
1389 ["\\begin_inset CommandInset url", "LatexCommand url"]
1390 i = i + 2
1392 def revert_url(document):
1393 'Reverts Flex URL insets to old-style URL insets'
1394 i = 0
1395 while True:
1396 i = find_token(document.body, "\\begin_inset Flex URL", i)
1397 if i == -1:
1398 return
1399 j = find_end_of_inset(document.body, i)
1400 if j == -1:
1401 document.warning("Can't find end of inset in revert_url!")
1402 return
1403 k = find_default_layout(document, i, j)
1404 if k == -1:
1405 document.warning("Can't find default layout in revert_url!")
1406 i = j
1407 continue
1408 l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1409 if l == -1 or l >= j:
1410 document.warning("Can't find end of default layout in revert_url!")
1411 i = j
1412 continue
1413 # OK, so the inset's data is between lines k and l.
1414 data = " ".join(document.body[k+1:l])
1415 data = data.strip()
1416 newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1417 "", "\\end_inset"]
1418 document.body[i:j+1] = newinset
1419 i = i + len(newinset)
1422 def convert_include(document):
1423 'Converts include insets to new format.'
1424 i = 0
1425 r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1426 while True:
1427 i = find_token(document.body, "\\begin_inset Include", i)
1428 if i == -1:
1429 return
1430 line = document.body[i]
1431 previewline = document.body[i + 1]
1432 m = r.match(line)
1433 if m == None:
1434 document.warning("Unable to match line " + str(i) + " of body!")
1435 i += 1
1436 continue
1437 cmd = m.group(1)
1438 fn = m.group(2)
1439 opt = m.group(3)
1440 insertion = ["\\begin_inset CommandInset include",
1441 "LatexCommand " + cmd, previewline,
1442 "filename \"" + fn + "\""]
1443 newlines = 2
1444 if opt:
1445 insertion.append("lstparams " + '"' + opt + '"')
1446 newlines += 1
1447 document.body[i : i + 2] = insertion
1448 i += newlines
1451 def revert_include(document):
1452 'Reverts include insets to old format.'
1453 i = 0
1454 r0 = re.compile('preview.*')
1455 r1 = re.compile('LatexCommand (.+)')
1456 r2 = re.compile('filename "(.+)"')
1457 r3 = re.compile('lstparams "(.*)"')
1458 while True:
1459 i = find_token(document.body, "\\begin_inset CommandInset include", i)
1460 if i == -1:
1461 return
1462 nextline = i + 1
1463 m = r1.match(document.body[nextline])
1464 if m == None:
1465 document.warning("Malformed LyX document: No LatexCommand line for `" +
1466 document.body[i] + "' on line " + str(i) + ".")
1467 i += 1
1468 continue
1469 cmd = m.group(1)
1470 nextline += 1
1471 if r0.match(document.body[nextline]):
1472 previewline = document.body[nextline]
1473 nextline += 1
1474 else:
1475 previewline = ""
1476 m = r2.match(document.body[nextline])
1477 if m == None:
1478 document.warning("Malformed LyX document: No filename line for `" + \
1479 document.body[i] + "' on line " + str(i) + ".")
1480 i += 2
1481 continue
1482 fn = m.group(1)
1483 nextline += 1
1484 options = ""
1485 if (cmd == "lstinputlisting"):
1486 m = r3.match(document.body[nextline])
1487 if m != None:
1488 options = m.group(1)
1489 numlines = 5
1490 nextline += 1
1491 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1492 if options:
1493 newline += ("[" + options + "]")
1494 insertion = [newline]
1495 if previewline != "":
1496 insertion.append(previewline)
1497 document.body[i : nextline] = insertion
1498 i += 2
1501 def revert_albanian(document):
1502 "Set language Albanian to English"
1503 i = 0
1504 if document.language == "albanian":
1505 document.language = "english"
1506 i = find_token(document.header, "\\language", 0)
1507 if i != -1:
1508 document.header[i] = "\\language english"
1509 j = 0
1510 while True:
1511 j = find_token(document.body, "\\lang albanian", j)
1512 if j == -1:
1513 return
1514 document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1515 j = j + 1
1518 def revert_lowersorbian(document):
1519 "Set language lower Sorbian to English"
1520 i = 0
1521 if document.language == "lowersorbian":
1522 document.language = "english"
1523 i = find_token(document.header, "\\language", 0)
1524 if i != -1:
1525 document.header[i] = "\\language english"
1526 j = 0
1527 while True:
1528 j = find_token(document.body, "\\lang lowersorbian", j)
1529 if j == -1:
1530 return
1531 document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1532 j = j + 1
1535 def revert_uppersorbian(document):
1536 "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1537 i = 0
1538 if document.language == "uppersorbian":
1539 document.language = "usorbian"
1540 i = find_token(document.header, "\\language", 0)
1541 if i != -1:
1542 document.header[i] = "\\language usorbian"
1543 j = 0
1544 while True:
1545 j = find_token(document.body, "\\lang uppersorbian", j)
1546 if j == -1:
1547 return
1548 document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1549 j = j + 1
1552 def convert_usorbian(document):
1553 "Set language usorbian to uppersorbian"
1554 i = 0
1555 if document.language == "usorbian":
1556 document.language = "uppersorbian"
1557 i = find_token(document.header, "\\language", 0)
1558 if i != -1:
1559 document.header[i] = "\\language uppersorbian"
1560 j = 0
1561 while True:
1562 j = find_token(document.body, "\\lang usorbian", j)
1563 if j == -1:
1564 return
1565 document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1566 j = j + 1
1569 def convert_macro_global(document):
1570 "Remove TeX code command \global when it is in front of a macro"
1571 # math macros are nowadays already defined \global, so that an additional
1572 # \global would make the document uncompilable, see
1573 # http://bugzilla.lyx.org/show_bug.cgi?id=5371
1574 # We're looking for something like this:
1575 # \begin_inset ERT
1576 # status collapsed
1578 # \begin_layout Plain Layout
1581 # \backslash
1582 # global
1583 # \end_layout
1585 # \end_inset
1588 # \begin_inset FormulaMacro
1589 # \renewcommand{\foo}{123}
1590 # \end_inset
1591 i = 0
1592 while True:
1593 i = find_token(document.body, "\\begin_inset FormulaMacro", i)
1594 if i == -1:
1595 return
1596 # if i <= 13, then there isn't enough room for the ERT
1597 if i <= 12:
1598 i += 1
1599 continue
1600 if document.body[i-6] == "global":
1601 del document.body[i-13 : i]
1602 i = i - 12
1603 else:
1604 i += 1
1607 def revert_macro_optional_params(document):
1608 "Convert macro definitions with optional parameters into ERTs"
1609 # Stub to convert macro definitions with one or more optional parameters
1610 # into uninterpreted ERT insets
1613 def revert_hyperlinktype(document):
1614 'Reverts hyperlink type'
1615 i = 0
1616 j = 0
1617 while True:
1618 i = find_token(document.body, "target", i)
1619 if i == -1:
1620 return
1621 j = find_token(document.body, "type", i)
1622 if j == -1:
1623 return
1624 if j == i + 1:
1625 del document.body[j]
1626 i = i + 1
1629 def revert_pagebreak(document):
1630 'Reverts pagebreak to ERT'
1631 i = 0
1632 while True:
1633 i = find_token(document.body, "\\pagebreak", i)
1634 if i == -1:
1635 return
1636 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1637 '\\begin_layout Standard\n\n\n\\backslash\n' \
1638 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1639 i = i + 1
1642 def revert_linebreak(document):
1643 'Reverts linebreak to ERT'
1644 i = 0
1645 while True:
1646 i = find_token(document.body, "\\linebreak", i)
1647 if i == -1:
1648 return
1649 document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1650 '\\begin_layout Standard\n\n\n\\backslash\n' \
1651 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1652 i = i + 1
1655 def revert_latin(document):
1656 "Set language Latin to English"
1657 i = 0
1658 if document.language == "latin":
1659 document.language = "english"
1660 i = find_token(document.header, "\\language", 0)
1661 if i != -1:
1662 document.header[i] = "\\language english"
1663 j = 0
1664 while True:
1665 j = find_token(document.body, "\\lang latin", j)
1666 if j == -1:
1667 return
1668 document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1669 j = j + 1
1672 def revert_samin(document):
1673 "Set language North Sami to English"
1674 i = 0
1675 if document.language == "samin":
1676 document.language = "english"
1677 i = find_token(document.header, "\\language", 0)
1678 if i != -1:
1679 document.header[i] = "\\language english"
1680 j = 0
1681 while True:
1682 j = find_token(document.body, "\\lang samin", j)
1683 if j == -1:
1684 return
1685 document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1686 j = j + 1
1689 def convert_serbocroatian(document):
1690 "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1691 i = 0
1692 if document.language == "serbocroatian":
1693 document.language = "croatian"
1694 i = find_token(document.header, "\\language", 0)
1695 if i != -1:
1696 document.header[i] = "\\language croatian"
1697 j = 0
1698 while True:
1699 j = find_token(document.body, "\\lang serbocroatian", j)
1700 if j == -1:
1701 return
1702 document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1703 j = j + 1
1706 def convert_framed_notes(document):
1707 "Convert framed notes to boxes. "
1708 i = 0
1709 while 1:
1710 i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1711 if i == -1:
1712 return
1713 subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1714 'position "t"',
1715 'hor_pos "c"',
1716 'has_inner_box 0',
1717 'inner_pos "t"',
1718 'use_parbox 0',
1719 'width "100col%"',
1720 'special "none"',
1721 'height "1in"',
1722 'height_special "totalheight"']
1723 document.body[i:i+1] = subst
1724 i = i + 9
1727 def convert_module_names(document):
1728 modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1729 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1730 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1731 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1732 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1733 modlist = document.get_module_list()
1734 if len(modlist) == 0:
1735 return
1736 newmodlist = []
1737 for mod in modlist:
1738 if modulemap.has_key(mod):
1739 newmodlist.append(modulemap[mod])
1740 else:
1741 document.warning("Can't find module %s in the module map!" % mod)
1742 newmodlist.append(mod)
1743 document.set_module_list(newmodlist)
1746 def revert_module_names(document):
1747 modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1748 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1749 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1750 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1751 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1752 modlist = document.get_module_list()
1753 if len(modlist) == 0:
1754 return
1755 newmodlist = []
1756 for mod in modlist:
1757 if modulemap.has_key(mod):
1758 newmodlist.append(modulemap[mod])
1759 else:
1760 document.warning("Can't find module %s in the module map!" % mod)
1761 newmodlist.append(mod)
1762 document.set_module_list(newmodlist)
1765 def revert_colsep(document):
1766 i = find_token(document.header, "\\columnsep", 0)
1767 if i == -1:
1768 return
1769 colsepline = document.header[i]
1770 r = re.compile(r'\\columnsep (.*)')
1771 m = r.match(colsepline)
1772 if not m:
1773 document.warning("Malformed column separation line!")
1774 return
1775 colsep = m.group(1)
1776 del document.header[i]
1777 #it seems to be safe to add the package even if it is already used
1778 pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1780 add_to_preamble(document, pretext)
1783 def revert_framed_notes(document):
1784 "Revert framed boxes to notes. "
1785 i = 0
1786 while 1:
1787 i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1789 if i == -1:
1790 return
1791 j = find_end_of_inset(document.body, i + 1)
1792 if j == -1:
1793 # should not happen
1794 document.warning("Malformed LyX document: Could not find end of Box inset.")
1795 k = find_token(document.body, "status", i + 1, j)
1796 if k == -1:
1797 document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1798 return
1799 status = document.body[k]
1800 l = find_default_layout(document, i + 1, j)
1801 if l == -1:
1802 document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1803 return
1804 m = find_token(document.body, "\\end_layout", i + 1, j)
1805 if m == -1:
1806 document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1807 return
1808 ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1809 pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1810 if ibox == -1 and pbox == -1:
1811 document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1812 del document.body[i+1:k]
1813 else:
1814 document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1815 subst1 = [document.body[l],
1816 "\\begin_inset Note Shaded",
1817 status,
1818 '\\begin_layout Standard']
1819 document.body[l:l + 1] = subst1
1820 subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1821 document.body[m:m + 1] = subst2
1822 i = i + 1
1825 def revert_slash(document):
1826 'Revert \\SpecialChar \\slash{} to ERT'
1827 i = 0
1828 while i < len(document.body):
1829 m = re.match(r'(.*)\\SpecialChar \\slash{}(.*)', document.body[i])
1830 if m:
1831 before = m.group(1)
1832 after = m.group(2)
1833 subst = [before,
1834 '\\begin_inset ERT',
1835 'status collapsed', '',
1836 '\\begin_layout Standard',
1837 '', '', '\\backslash',
1838 'slash{}',
1839 '\\end_layout', '',
1840 '\\end_inset', '',
1841 after]
1842 document.body[i: i+1] = subst
1843 i = i + len(subst)
1844 else:
1845 i = i + 1
1848 def revert_nobreakdash(document):
1849 'Revert \\SpecialChar \\nobreakdash- to ERT'
1850 i = 0
1851 while i < len(document.body):
1852 m = re.match(r'(.*)\\SpecialChar \\nobreakdash-(.*)', document.body[i])
1853 if m:
1854 before = m.group(1)
1855 after = m.group(2)
1856 subst = [before,
1857 '\\begin_inset ERT',
1858 'status collapsed', '',
1859 '\\begin_layout Standard', '', '',
1860 '\\backslash',
1861 'nobreakdash-',
1862 '\\end_layout', '',
1863 '\\end_inset', '',
1864 after]
1865 document.body[i: i+1] = subst
1866 i = i + len(subst)
1867 j = find_token(document.header, "\\use_amsmath", 0)
1868 if j == -1:
1869 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1870 return
1871 document.header[j] = "\\use_amsmath 2"
1872 else:
1873 i = i + 1
1876 #Returns number of lines added/removed
1877 def revert_nocite_key(body, start, end):
1878 'key "..." -> \nocite{...}'
1879 r = re.compile(r'^key "(.*)"')
1880 i = start
1881 j = end
1882 while i < j:
1883 m = r.match(body[i])
1884 if m:
1885 body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1886 j += 1 # because we added a line
1887 i += 2 # skip that line
1888 else:
1889 del body[i]
1890 j -= 1 # because we deleted a line
1891 # no need to change i, since it now points to the next line
1892 return j - end
1895 def revert_nocite(document):
1896 "Revert LatexCommand nocite to ERT"
1897 i = 0
1898 while 1:
1899 i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1900 if i == -1:
1901 return
1902 if (document.body[i+1] != "LatexCommand nocite"):
1903 # note that we already incremented i
1904 i = i + 1
1905 continue
1906 insetEnd = find_end_of_inset(document.body, i)
1907 if insetEnd == -1:
1908 #this should not happen
1909 document.warning("End of CommandInset citation not found in revert_nocite!")
1910 return
1912 paramLocation = i + 2 #start of the inset's parameters
1913 addedLines = 0
1914 document.body[i:i+2] = \
1915 ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1916 # that added two lines
1917 paramLocation += 2
1918 insetEnd += 2
1919 #print insetEnd, document.body[i: insetEnd + 1]
1920 insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1921 #print insetEnd, document.body[i: insetEnd + 1]
1922 document.body.insert(insetEnd, "\\end_layout")
1923 document.body.insert(insetEnd + 1, "")
1924 i = insetEnd + 1
1927 def revert_btprintall(document):
1928 "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1929 i = find_token(document.header, '\\use_bibtopic', 0)
1930 if i == -1:
1931 document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1932 return
1933 if get_value(document.header, '\\use_bibtopic', 0) == "false":
1934 i = 0
1935 while i < len(document.body):
1936 i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1937 if i == -1:
1938 return
1939 j = find_end_of_inset(document.body, i + 1)
1940 if j == -1:
1941 #this should not happen
1942 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1943 j = len(document.body)
1944 # this range isn't really right, but it should be OK, since we shouldn't
1945 # see more than one matching line in each inset
1946 addedlines = 0
1947 for k in range(i, j):
1948 if (document.body[k] == 'btprint "btPrintAll"'):
1949 del document.body[k]
1950 subst = ["\\begin_inset ERT",
1951 "status collapsed", "",
1952 "\\begin_layout Standard", "",
1953 "\\backslash",
1954 "nocite{*}",
1955 "\\end_layout",
1956 "\\end_inset"]
1957 document.body[i:i] = subst
1958 addlines = addedlines + len(subst) - 1
1959 i = j + addedlines
1962 def revert_bahasam(document):
1963 "Set language Bahasa Malaysia to Bahasa Indonesia"
1964 i = 0
1965 if document.language == "bahasam":
1966 document.language = "bahasa"
1967 i = find_token(document.header, "\\language", 0)
1968 if i != -1:
1969 document.header[i] = "\\language bahasa"
1970 j = 0
1971 while True:
1972 j = find_token(document.body, "\\lang bahasam", j)
1973 if j == -1:
1974 return
1975 document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1976 j = j + 1
1979 def revert_interlingua(document):
1980 "Set language Interlingua to English"
1981 i = 0
1982 if document.language == "interlingua":
1983 document.language = "english"
1984 i = find_token(document.header, "\\language", 0)
1985 if i != -1:
1986 document.header[i] = "\\language english"
1987 j = 0
1988 while True:
1989 j = find_token(document.body, "\\lang interlingua", j)
1990 if j == -1:
1991 return
1992 document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1993 j = j + 1
1996 def revert_serbianlatin(document):
1997 "Set language Serbian-Latin to Croatian"
1998 i = 0
1999 if document.language == "serbian-latin":
2000 document.language = "croatian"
2001 i = find_token(document.header, "\\language", 0)
2002 if i != -1:
2003 document.header[i] = "\\language croatian"
2004 j = 0
2005 while True:
2006 j = find_token(document.body, "\\lang serbian-latin", j)
2007 if j == -1:
2008 return
2009 document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
2010 j = j + 1
2013 def revert_rotfloat(document):
2014 " Revert sideways custom floats. "
2015 i = 0
2016 while 1:
2017 # whitespace intended (exclude \\begin_inset FloatList)
2018 i = find_token(document.body, "\\begin_inset Float ", i)
2019 if i == -1:
2020 return
2021 line = document.body[i]
2022 r = re.compile(r'\\begin_inset Float (.*)$')
2023 m = r.match(line)
2024 if m == None:
2025 document.warning("Unable to match line " + str(i) + " of body!")
2026 i += 1
2027 continue
2028 floattype = m.group(1)
2029 if floattype == "figure" or floattype == "table":
2030 i += 1
2031 continue
2032 j = find_end_of_inset(document.body, i)
2033 if j == -1:
2034 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
2035 i += 1
2036 continue
2037 addedLines = 0
2038 if get_value(document.body, 'sideways', i, j) == "false":
2039 i += 1
2040 continue
2041 l = find_default_layout(document, i + 1, j)
2042 if l == -1:
2043 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2044 return
2045 subst = ['\\begin_layout Standard',
2046 '\\begin_inset ERT',
2047 'status collapsed', '',
2048 '\\begin_layout Standard', '', '',
2049 '\\backslash', '',
2050 'end{sideways' + floattype + '}',
2051 '\\end_layout', '', '\\end_inset']
2052 document.body[j : j+1] = subst
2053 addedLines = len(subst) - 1
2054 del document.body[i+1 : l]
2055 addedLines -= (l-1) - (i+1)
2056 subst = ['\\begin_inset ERT', 'status collapsed', '',
2057 '\\begin_layout Standard', '', '', '\\backslash',
2058 'begin{sideways' + floattype + '}',
2059 '\\end_layout', '', '\\end_inset', '',
2060 '\\end_layout', '']
2061 document.body[i : i+1] = subst
2062 addedLines += len(subst) - 1
2063 if floattype == "algorithm":
2064 add_to_preamble(document,
2065 ['% Commands inserted by lyx2lyx for sideways algorithm float',
2066 '\\usepackage{rotfloat}',
2067 '\\floatstyle{ruled}',
2068 '\\newfloat{algorithm}{tbp}{loa}',
2069 '\\floatname{algorithm}{Algorithm}'])
2070 else:
2071 document.warning("Cannot create preamble definition for custom float" + floattype + ".")
2072 i += addedLines + 1
2075 def revert_widesideways(document):
2076 " Revert wide sideways floats. "
2077 i = 0
2078 while 1:
2079 # whitespace intended (exclude \\begin_inset FloatList)
2080 i = find_token(document.body, '\\begin_inset Float ', i)
2081 if i == -1:
2082 return
2083 line = document.body[i]
2084 r = re.compile(r'\\begin_inset Float (.*)$')
2085 m = r.match(line)
2086 if m == None:
2087 document.warning("Unable to match line " + str(i) + " of body!")
2088 i += 1
2089 continue
2090 floattype = m.group(1)
2091 if floattype != "figure" and floattype != "table":
2092 i += 1
2093 continue
2094 j = find_end_of_inset(document.body, i)
2095 if j == -1:
2096 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2097 i += 1
2098 continue
2099 if get_value(document.body, 'sideways', i, j) == "false" or \
2100 get_value(document.body, 'wide', i, j) == "false":
2101 i += 1
2102 continue
2103 l = find_default_layout(document, i + 1, j)
2104 if l == -1:
2105 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2106 return
2107 subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2108 'status collapsed', '',
2109 '\\begin_layout Standard', '', '', '\\backslash',
2110 'end{sideways' + floattype + '*}',
2111 '\\end_layout', '', '\\end_inset']
2112 document.body[j : j+1] = subst
2113 addedLines = len(subst) - 1
2114 del document.body[i+1:l-1]
2115 addedLines -= (l-1) - (i+1)
2116 subst = ['\\begin_inset ERT', 'status collapsed', '',
2117 '\\begin_layout Standard', '', '', '\\backslash',
2118 'begin{sideways' + floattype + '*}', '\\end_layout', '',
2119 '\\end_inset', '', '\\end_layout', '']
2120 document.body[i : i+1] = subst
2121 addedLines += len(subst) - 1
2122 add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2123 i += addedLines + 1
2126 def revert_inset_embedding(document, type):
2127 ' Remove embed tag from certain type of insets'
2128 i = 0
2129 while 1:
2130 i = find_token(document.body, "\\begin_inset %s" % type, i)
2131 if i == -1:
2132 return
2133 j = find_end_of_inset(document.body, i)
2134 if j == -1:
2135 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2136 i = i + 1
2137 continue
2138 k = find_token(document.body, "\tembed", i, j)
2139 if k == -1:
2140 k = find_token(document.body, "embed", i, j)
2141 if k != -1:
2142 del document.body[k]
2143 i = i + 1
2146 def revert_external_embedding(document):
2147 ' Remove embed tag from external inset '
2148 revert_inset_embedding(document, 'External')
2151 def convert_subfig(document):
2152 " Convert subfigures to subfloats. "
2153 i = 0
2154 while 1:
2155 addedLines = 0
2156 i = find_token(document.body, '\\begin_inset Graphics', i)
2157 if i == -1:
2158 return
2159 endInset = find_end_of_inset(document.body, i)
2160 if endInset == -1:
2161 document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2162 i += 1
2163 continue
2164 k = find_token(document.body, '\tsubcaption', i, endInset)
2165 if k == -1:
2166 i = endInset
2167 continue
2168 l = find_token(document.body, '\tsubcaptionText', i, endInset)
2169 if l == -1:
2170 caption = ""
2171 else:
2172 caption = document.body[l][16:].strip('"')
2173 del document.body[l]
2174 addedLines -= 1
2175 del document.body[k]
2176 addedLines -= 1
2177 subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2178 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2179 '', '\\begin_layout Plain Layout'] + latex2lyx(caption) + \
2180 [ '\\end_layout', '', '\\end_inset', '',
2181 '\\end_layout', '', '\\begin_layout Plain Layout']
2182 document.body[i : i] = subst
2183 addedLines += len(subst)
2184 endInset += addedLines
2185 subst = ['', '\\end_inset', '', '\\end_layout']
2186 document.body[endInset : endInset] = subst
2187 addedLines += len(subst)
2188 i += addedLines + 1
2191 def revert_subfig(document):
2192 " Revert subfloats. "
2193 i = 0
2194 while 1:
2195 # whitespace intended (exclude \\begin_inset FloatList)
2196 i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2197 if i == -1:
2198 return
2199 j = 0
2200 addedLines = 0
2201 while j != -1:
2202 j = find_end_of_inset(document.body, i)
2203 if j == -1:
2204 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2205 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2206 i += 1
2207 continue # this will get us back to the outer loop, since j == -1
2208 # look for embedded float (= subfloat)
2209 # whitespace intended (exclude \\begin_inset FloatList)
2210 k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2211 if k == -1:
2212 break
2213 # is the subfloat aligned?
2214 al = find_token(document.body, '\\align ', k - 1, j)
2215 alignment_beg = ""
2216 alignment_end = ""
2217 if al != -1:
2218 if get_value(document.body, '\\align', al) == "center":
2219 alignment_beg = "\\backslash\nbegin{centering}"
2220 alignment_end = "\\backslash\npar\\backslash\nend{centering}"
2221 elif get_value(document.body, '\\align', al) == "left":
2222 alignment_beg = "\\backslash\nbegin{raggedright}"
2223 alignment_end = "\\backslash\npar\\backslash\nend{raggedright}"
2224 elif get_value(document.body, '\\align', al) == "right":
2225 alignment_beg = "\\backslash\nbegin{raggedleft}"
2226 alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}"
2227 l = find_end_of_inset(document.body, k)
2228 if l == -1:
2229 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2230 i += 1
2231 j = -1
2232 continue # escape to the outer loop
2233 m = find_default_layout(document, k + 1, l)
2234 # caption?
2235 cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2236 caption = ''
2237 shortcap = ''
2238 capend = cap
2239 if cap != -1:
2240 capend = find_end_of_inset(document.body, cap)
2241 if capend == -1:
2242 document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2243 return
2244 # label?
2245 label = ''
2246 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2247 if lbl != -1:
2248 lblend = find_end_of_inset(document.body, lbl + 1)
2249 if lblend == -1:
2250 document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2251 return
2252 for line in document.body[lbl:lblend + 1]:
2253 if line.startswith('name '):
2254 label = line.split()[1].strip('"')
2255 break
2256 else:
2257 lbl = capend
2258 lblend = capend
2259 label = ''
2260 # opt arg?
2261 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2262 if opt != -1:
2263 optend = find_end_of_inset(document.body, opt)
2264 if optend == -1:
2265 document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
2266 return
2267 optc = find_default_layout(document, opt, optend)
2268 if optc == -1:
2269 document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2270 return
2271 optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2272 for line in document.body[optc:optcend]:
2273 if not line.startswith('\\'):
2274 shortcap += line.strip()
2275 else:
2276 opt = capend
2277 optend = capend
2278 for line in document.body[cap:capend]:
2279 if line in document.body[lbl:lblend]:
2280 continue
2281 elif line in document.body[opt:optend]:
2282 continue
2283 else:
2284 inert = True
2285 caption += lyxline2latex(document, line, inert)
2286 if len(label) > 0:
2287 caption += "\n\\backslash\nlabel{" + label + "}"
2288 subst = '\\begin_layout PlainLayout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2289 '\\begin_layout PlainLayout\n\n}' + alignment_end + \
2290 '\n\\end_layout\n\n\\end_inset\n\n' \
2291 '\\end_layout\n\n\\begin_layout PlainLayout\n'
2292 subst = subst.split('\n')
2293 document.body[l : l+1] = subst
2294 addedLines = len(subst) - 1
2295 # this is before l and so is unchanged by the multiline insertion
2296 if cap != capend:
2297 del document.body[cap:capend+1]
2298 addedLines -= (capend + 1 - cap)
2299 del document.body[k+1:m-1]
2300 addedLines -= (m - 1 - (k + 1))
2301 insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2302 '\\begin_layout PlainLayout\n\n' + alignment_beg + '\n\\backslash\n' \
2303 'subfloat'
2304 if len(shortcap) > 0:
2305 insertion = insertion + "[" + shortcap + "]"
2306 if len(caption) > 0:
2307 insertion = insertion + "[" + caption + "]"
2308 insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2309 insertion = insertion.split('\n')
2310 document.body[k : k + 1] = insertion
2311 addedLines += len(insertion) - 1
2312 al = find_token(document.body, '\\align ', k - 1, j + addedLines)
2313 if al != -1:
2314 del document.body[al]
2315 addedLines -= 1
2316 add_to_preamble(document, ['\\usepackage{subfig}\n'])
2317 i += addedLines + 1
2320 def revert_wrapplacement(document):
2321 " Revert placement options wrap floats (wrapfig). "
2322 i = 0
2323 while True:
2324 i = find_token(document.body, "\\begin_inset Wrap figure", i)
2325 if i == -1:
2326 return
2327 e = find_end_of_inset(document.body, i)
2328 j = find_token(document.body, "placement", i + 1, e)
2329 if j == -1:
2330 document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2331 i += 1
2332 continue
2333 r = re.compile("placement (o|i|l|r|O|I|L|R)")
2334 m = r.match(document.body[j])
2335 if m == None:
2336 document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2337 else:
2338 document.body[j] = "placement " + m.group(1).lower()
2339 i = j
2342 def remove_extra_embedded_files(document):
2343 " Remove \extra_embedded_files from buffer params "
2344 i = find_token(document.header, '\\extra_embedded_files', 0)
2345 if i == -1:
2346 return
2347 document.header.pop(i)
2350 def convert_spaceinset(document):
2351 " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2352 i = 0
2353 while i < len(document.body):
2354 m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2355 if m:
2356 before = m.group(1)
2357 after = m.group(2)
2358 subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2359 document.body[i: i+1] = subst
2360 i = i + len(subst)
2361 else:
2362 i = i + 1
2365 def revert_spaceinset(document):
2366 " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2367 i = 0
2368 while True:
2369 i = find_token(document.body, "\\begin_inset Space", i)
2370 if i == -1:
2371 return
2372 j = find_end_of_inset(document.body, i)
2373 if j == -1:
2374 document.warning("Malformed LyX document: Could not find end of space inset.")
2375 continue
2376 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2377 del document.body[j]
2380 def convert_hfill(document):
2381 " Convert hfill to space inset "
2382 i = 0
2383 while True:
2384 i = find_token(document.body, "\\hfill", i)
2385 if i == -1:
2386 return
2387 subst = document.body[i].replace('\\hfill', \
2388 '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2389 subst = subst.split('\n')
2390 document.body[i : i+1] = subst
2391 i += len(subst)
2394 def revert_hfills(document):
2395 ' Revert \\hfill commands '
2396 hfill = re.compile(r'\\hfill')
2397 dotfill = re.compile(r'\\dotfill')
2398 hrulefill = re.compile(r'\\hrulefill')
2399 i = 0
2400 while True:
2401 i = find_token(document.body, "\\InsetSpace", i)
2402 if i == -1:
2403 return
2404 if hfill.search(document.body[i]):
2405 document.body[i] = \
2406 document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2407 i += 1
2408 continue
2409 if dotfill.search(document.body[i]):
2410 subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2411 '\\begin_inset ERT\nstatus collapsed\n\n' \
2412 '\\begin_layout Standard\n\n\n\\backslash\n' \
2413 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2414 subst = subst.split('\n')
2415 document.body[i : i+1] = subst
2416 i += len(subst)
2417 continue
2418 if hrulefill.search(document.body[i]):
2419 subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2420 '\\begin_inset ERT\nstatus collapsed\n\n' \
2421 '\\begin_layout Standard\n\n\n\\backslash\n' \
2422 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2423 subst = subst.split('\n')
2424 document.body[i : i+1] = subst
2425 i += len(subst)
2426 continue
2427 i += 1
2429 def revert_hspace(document):
2430 ' Revert \\InsetSpace \\hspace{} to ERT '
2431 i = 0
2432 hspace = re.compile(r'\\hspace{}')
2433 hstar = re.compile(r'\\hspace\*{}')
2434 while True:
2435 i = find_token(document.body, "\\InsetSpace \\hspace", i)
2436 if i == -1:
2437 return
2438 length = get_value(document.body, '\\length', i+1)
2439 if length == '':
2440 document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2441 return
2442 del document.body[i+1]
2443 addedLines = -1
2444 if hstar.search(document.body[i]):
2445 subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2446 '\\begin_inset ERT\nstatus collapsed\n\n' \
2447 '\\begin_layout Standard\n\n\n\\backslash\n' \
2448 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2449 subst = subst.split('\n')
2450 document.body[i : i+1] = subst
2451 addedLines += len(subst) - 1
2452 i += addedLines + 1
2453 continue
2454 if hspace.search(document.body[i]):
2455 subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2456 '\\begin_inset ERT\nstatus collapsed\n\n' \
2457 '\\begin_layout Standard\n\n\n\\backslash\n' \
2458 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2459 subst = subst.split('\n')
2460 document.body[i : i+1] = subst
2461 addedLines += len(subst) - 1
2462 i += addedLines + 1
2463 continue
2464 i += 1
2467 def revert_protected_hfill(document):
2468 ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2469 i = 0
2470 while True:
2471 i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2472 if i == -1:
2473 return
2474 j = find_end_of_inset(document.body, i)
2475 if j == -1:
2476 document.warning("Malformed LyX document: Could not find end of space inset.")
2477 continue
2478 del document.body[j]
2479 subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2480 '\\begin_inset ERT\nstatus collapsed\n\n' \
2481 '\\begin_layout Standard\n\n\n\\backslash\n' \
2482 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2483 subst = subst.split('\n')
2484 document.body[i : i+1] = subst
2485 i += len(subst)
2488 def revert_leftarrowfill(document):
2489 ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2490 i = 0
2491 while True:
2492 i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2493 if i == -1:
2494 return
2495 j = find_end_of_inset(document.body, i)
2496 if j == -1:
2497 document.warning("Malformed LyX document: Could not find end of space inset.")
2498 continue
2499 del document.body[j]
2500 subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2501 '\\begin_inset ERT\nstatus collapsed\n\n' \
2502 '\\begin_layout Standard\n\n\n\\backslash\n' \
2503 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2504 subst = subst.split('\n')
2505 document.body[i : i+1] = subst
2506 i += len(subst)
2509 def revert_rightarrowfill(document):
2510 ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2511 i = 0
2512 while True:
2513 i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2514 if i == -1:
2515 return
2516 j = find_end_of_inset(document.body, i)
2517 if j == -1:
2518 document.warning("Malformed LyX document: Could not find end of space inset.")
2519 continue
2520 del document.body[j]
2521 subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2522 '\\begin_inset ERT\nstatus collapsed\n\n' \
2523 '\\begin_layout Standard\n\n\n\\backslash\n' \
2524 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2525 subst = subst.split('\n')
2526 document.body[i : i+1] = subst
2527 i += len(subst)
2530 def revert_upbracefill(document):
2531 ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2532 i = 0
2533 while True:
2534 i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2535 if i == -1:
2536 return
2537 j = find_end_of_inset(document.body, i)
2538 if j == -1:
2539 document.warning("Malformed LyX document: Could not find end of space inset.")
2540 continue
2541 del document.body[j]
2542 subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2543 '\\begin_inset ERT\nstatus collapsed\n\n' \
2544 '\\begin_layout Standard\n\n\n\\backslash\n' \
2545 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2546 subst = subst.split('\n')
2547 document.body[i : i+1] = subst
2548 i += len(subst)
2551 def revert_downbracefill(document):
2552 ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2553 i = 0
2554 while True:
2555 i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2556 if i == -1:
2557 return
2558 j = find_end_of_inset(document.body, i)
2559 if j == -1:
2560 document.warning("Malformed LyX document: Could not find end of space inset.")
2561 continue
2562 del document.body[j]
2563 subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2564 '\\begin_inset ERT\nstatus collapsed\n\n' \
2565 '\\begin_layout Standard\n\n\n\\backslash\n' \
2566 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2567 subst = subst.split('\n')
2568 document.body[i : i+1] = subst
2569 i += len(subst)
2572 def revert_local_layout(document):
2573 ' Revert local layout headers.'
2574 i = 0
2575 while True:
2576 i = find_token(document.header, "\\begin_local_layout", i)
2577 if i == -1:
2578 return
2579 j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2580 if j == -1:
2581 # this should not happen
2582 break
2583 document.header[i : j + 1] = []
2586 def convert_pagebreaks(document):
2587 ' Convert inline Newpage insets to new format '
2588 i = 0
2589 while True:
2590 i = find_token(document.body, '\\newpage', i)
2591 if i == -1:
2592 break
2593 document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2594 '\\end_inset']
2595 i = 0
2596 while True:
2597 i = find_token(document.body, '\\pagebreak', i)
2598 if i == -1:
2599 break
2600 document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2601 '\\end_inset']
2602 i = 0
2603 while True:
2604 i = find_token(document.body, '\\clearpage', i)
2605 if i == -1:
2606 break
2607 document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2608 '\\end_inset']
2609 i = 0
2610 while True:
2611 i = find_token(document.body, '\\cleardoublepage', i)
2612 if i == -1:
2613 break
2614 document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2615 '\\end_inset']
2618 def revert_pagebreaks(document):
2619 ' Revert \\begin_inset Newpage to previous inline format '
2620 i = 0
2621 while True:
2622 i = find_token(document.body, '\\begin_inset Newpage', i)
2623 if i == -1:
2624 return
2625 j = find_end_of_inset(document.body, i)
2626 if j == -1:
2627 document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2628 continue
2629 del document.body[j]
2630 document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2631 document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2632 document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2633 document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2636 def convert_linebreaks(document):
2637 ' Convert inline Newline insets to new format '
2638 i = 0
2639 while True:
2640 i = find_token(document.body, '\\newline', i)
2641 if i == -1:
2642 break
2643 document.body[i:i+1] = ['\\begin_inset Newline newline',
2644 '\\end_inset']
2645 i = 0
2646 while True:
2647 i = find_token(document.body, '\\linebreak', i)
2648 if i == -1:
2649 break
2650 document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2651 '\\end_inset']
2654 def revert_linebreaks(document):
2655 ' Revert \\begin_inset Newline to previous inline format '
2656 i = 0
2657 while True:
2658 i = find_token(document.body, '\\begin_inset Newline', i)
2659 if i == -1:
2660 return
2661 j = find_end_of_inset(document.body, i)
2662 if j == -1:
2663 document.warning("Malformed LyX document: Could not find end of Newline inset.")
2664 continue
2665 del document.body[j]
2666 document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2667 document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2670 def convert_japanese_plain(document):
2671 ' Set language japanese-plain to japanese '
2672 i = 0
2673 if document.language == "japanese-plain":
2674 document.language = "japanese"
2675 i = find_token(document.header, "\\language", 0)
2676 if i != -1:
2677 document.header[i] = "\\language japanese"
2678 j = 0
2679 while True:
2680 j = find_token(document.body, "\\lang japanese-plain", j)
2681 if j == -1:
2682 return
2683 document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2684 j = j + 1
2687 def revert_pdfpages(document):
2688 ' Revert pdfpages external inset to ERT '
2689 i = 0
2690 while 1:
2691 i = find_token(document.body, "\\begin_inset External", i)
2692 if i == -1:
2693 return
2694 j = find_end_of_inset(document.body, i)
2695 if j == -1:
2696 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2697 i = i + 1
2698 continue
2699 if get_value(document.body, 'template', i, j) == "PDFPages":
2700 filename = get_value(document.body, 'filename', i, j)
2701 extra = ''
2702 r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2703 for k in range(i, j):
2704 m = r.match(document.body[k])
2705 if m:
2706 extra = m.group(1)
2707 angle = get_value(document.body, 'rotateAngle', i, j)
2708 width = get_value(document.body, 'width', i, j)
2709 height = get_value(document.body, 'height', i, j)
2710 scale = get_value(document.body, 'scale', i, j)
2711 keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2712 options = extra
2713 if angle != '':
2714 if options != '':
2715 options += ",angle=" + angle
2716 else:
2717 options += "angle=" + angle
2718 if width != '':
2719 if options != '':
2720 options += ",width=" + convert_len(width)
2721 else:
2722 options += "width=" + convert_len(width)
2723 if height != '':
2724 if options != '':
2725 options += ",height=" + convert_len(height)
2726 else:
2727 options += "height=" + convert_len(height)
2728 if scale != '':
2729 if options != '':
2730 options += ",scale=" + scale
2731 else:
2732 options += "scale=" + scale
2733 if keepAspectRatio != '':
2734 if options != '':
2735 options += ",keepaspectratio"
2736 else:
2737 options += "keepaspectratio"
2738 if options != '':
2739 options = '[' + options + ']'
2740 del document.body[i+1:j+1]
2741 document.body[i:i+1] = ['\\begin_inset ERT',
2742 'status collapsed',
2744 '\\begin_layout Standard',
2746 '\\backslash',
2747 'includepdf' + options + '{' + filename + '}',
2748 '\\end_layout',
2750 '\\end_inset']
2751 add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2752 i = i + 1
2753 continue
2754 i = i + 1
2757 def revert_mexican(document):
2758 ' Set language Spanish(Mexico) to Spanish '
2759 i = 0
2760 if document.language == "spanish-mexico":
2761 document.language = "spanish"
2762 i = find_token(document.header, "\\language", 0)
2763 if i != -1:
2764 document.header[i] = "\\language spanish"
2765 j = 0
2766 while True:
2767 j = find_token(document.body, "\\lang spanish-mexico", j)
2768 if j == -1:
2769 return
2770 document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2771 j = j + 1
2774 def remove_embedding(document):
2775 ' Remove embed tag from all insets '
2776 revert_inset_embedding(document, 'Graphics')
2777 revert_inset_embedding(document, 'External')
2778 revert_inset_embedding(document, 'CommandInset include')
2779 revert_inset_embedding(document, 'CommandInset bibtex')
2782 def revert_master(document):
2783 ' Remove master param '
2784 i = find_token(document.header, "\\master", 0)
2785 if i != -1:
2786 del document.header[i]
2789 def revert_graphics_group(document):
2790 ' Revert group information from graphics insets '
2791 i = 0
2792 while 1:
2793 i = find_token(document.body, "\\begin_inset Graphics", i)
2794 if i == -1:
2795 return
2796 j = find_end_of_inset(document.body, i)
2797 if j == -1:
2798 document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2799 i = i + 1
2800 continue
2801 k = find_token(document.body, " groupId", i, j)
2802 if k == -1:
2803 i = i + 1
2804 continue
2805 del document.body[k]
2806 i = i + 1
2809 def update_apa_styles(document):
2810 ' Replace obsolete styles '
2812 if document.textclass != "apa":
2813 return
2815 obsoletedby = { "Acknowledgments": "Acknowledgements",
2816 "Section*": "Section",
2817 "Subsection*": "Subsection",
2818 "Subsubsection*": "Subsubsection",
2819 "Paragraph*": "Paragraph",
2820 "Subparagraph*": "Subparagraph"}
2821 i = 0
2822 while 1:
2823 i = find_token(document.body, "\\begin_layout", i)
2824 if i == -1:
2825 return
2827 layout = document.body[i][14:]
2828 if layout in obsoletedby:
2829 document.body[i] = "\\begin_layout " + obsoletedby[layout]
2831 i += 1
2834 def convert_paper_sizes(document):
2835 ' exchange size options legalpaper and executivepaper to correct order '
2836 # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2837 i = 0
2838 j = 0
2839 i = find_token(document.header, "\\papersize executivepaper", 0)
2840 if i != -1:
2841 document.header[i] = "\\papersize legalpaper"
2842 return
2843 j = find_token(document.header, "\\papersize legalpaper", 0)
2844 if j != -1:
2845 document.header[j] = "\\papersize executivepaper"
2848 def revert_paper_sizes(document):
2849 ' exchange size options legalpaper and executivepaper to correct order '
2850 i = 0
2851 j = 0
2852 i = find_token(document.header, "\\papersize executivepaper", 0)
2853 if i != -1:
2854 document.header[i] = "\\papersize legalpaper"
2855 return
2856 j = find_token(document.header, "\\papersize legalpaper", 0)
2857 if j != -1:
2858 document.header[j] = "\\papersize executivepaper"
2861 def convert_InsetSpace(document):
2862 " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2863 i = 0
2864 while True:
2865 i = find_token(document.body, "\\begin_inset Space", i)
2866 if i == -1:
2867 return
2868 document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2871 def revert_InsetSpace(document):
2872 " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2873 i = 0
2874 while True:
2875 i = find_token(document.body, "\\begin_inset space", i)
2876 if i == -1:
2877 return
2878 document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2881 def convert_display_enum(document):
2882 " Convert 'display foo' to 'display false/true'"
2883 i = 0
2884 while True:
2885 i = find_token(document.body, "\tdisplay", i)
2886 if i == -1:
2887 return
2888 val = get_value(document.body, 'display', i)
2889 if val == "none":
2890 document.body[i] = document.body[i].replace('none', 'false')
2891 if val == "default":
2892 document.body[i] = document.body[i].replace('default', 'true')
2893 if val == "monochrome":
2894 document.body[i] = document.body[i].replace('monochrome', 'true')
2895 if val == "grayscale":
2896 document.body[i] = document.body[i].replace('grayscale', 'true')
2897 if val == "color":
2898 document.body[i] = document.body[i].replace('color', 'true')
2899 if val == "preview":
2900 document.body[i] = document.body[i].replace('preview', 'true')
2901 i += 1
2904 def revert_display_enum(document):
2905 " Revert 'display false/true' to 'display none/color'"
2906 i = 0
2907 while True:
2908 i = find_token(document.body, "\tdisplay", i)
2909 if i == -1:
2910 return
2911 val = get_value(document.body, 'display', i)
2912 if val == "false":
2913 document.body[i] = document.body[i].replace('false', 'none')
2914 if val == "true":
2915 document.body[i] = document.body[i].replace('true', 'default')
2916 i += 1
2919 def remove_fontsCJK(document):
2920 ' Remove font_cjk param '
2921 i = find_token(document.header, "\\font_cjk", 0)
2922 if i != -1:
2923 del document.header[i]
2926 def convert_plain_layout(document):
2927 " Convert 'PlainLayout' to 'Plain Layout'"
2928 i = 0
2929 while True:
2930 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2931 if i == -1:
2932 return
2933 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2934 '\\begin_layout Plain Layout')
2935 i += 1
2938 def revert_plain_layout(document):
2939 " Revert 'Plain Layout' to 'PlainLayout'"
2940 i = 0
2941 while True:
2942 i = find_token(document.body, '\\begin_layout Plain Layout', i)
2943 if i == -1:
2944 return
2945 document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2946 '\\begin_layout PlainLayout')
2947 i += 1
2950 def revert_plainlayout(document):
2951 " Revert 'PlainLayout' to 'Standard'"
2952 i = 0
2953 while True:
2954 i = find_token(document.body, '\\begin_layout PlainLayout', i)
2955 if i == -1:
2956 return
2957 # This will be incorrect for some document classes, since Standard is not always
2958 # the default. But (a) it is probably the best we can do and (b) it will actually
2959 # work, in fact, since an unknown layout will be converted to default.
2960 document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2961 '\\begin_layout Standard')
2962 i += 1
2965 def revert_polytonicgreek(document):
2966 "Set language polytonic Greek to Greek"
2967 i = 0
2968 if document.language == "polutonikogreek":
2969 document.language = "greek"
2970 i = find_token(document.header, "\\language", 0)
2971 if i != -1:
2972 document.header[i] = "\\language greek"
2973 j = 0
2974 while True:
2975 j = find_token(document.body, "\\lang polutonikogreek", j)
2976 if j == -1:
2977 return
2978 document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2979 j = j + 1
2982 def revert_removed_modules(document):
2983 i = 0
2984 while True:
2985 i = find_token(document.header, "\\begin_remove_modules", i)
2986 if i == -1:
2987 return
2988 j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
2989 if j == -1:
2990 # this should not happen
2991 break
2992 document.header[i : j + 1] = []
2995 def add_plain_layout(document):
2996 i = 0
2997 while True:
2998 i = find_token(document.body, "\\begin_layout", i)
2999 if i == -1:
3000 return
3001 if len(document.body[i].split()) == 1:
3002 document.body[i] = "\\begin_layout Plain Layout"
3003 i += 1
3006 def revert_tabulators(document):
3007 "Revert tabulators to 4 spaces"
3008 i = 0
3009 while True:
3010 i = find_token(document.body, "\t", i)
3011 if i == -1:
3012 return
3013 document.body[i] = document.body[i].replace("\t", " ")
3014 i += 1
3017 def revert_tabsize(document):
3018 "Revert the tabsize parameter of listings"
3019 i = 0
3020 j = 0
3021 while True:
3022 # either it is the only parameter
3023 i = find_token(document.body, 'lstparams "tabsize=4"', i)
3024 if i != -1:
3025 del document.body[i]
3026 # or the last one
3027 j = find_token(document.body, "lstparams", j)
3028 if j == -1:
3029 return
3030 pos = document.body[j].find(",tabsize=")
3031 document.body[j] = document.body[j][:pos] + '"'
3032 i += 1
3033 j += 1
3036 def revert_mongolian(document):
3037 "Set language Mongolian to English"
3038 i = 0
3039 if document.language == "mongolian":
3040 document.language = "english"
3041 i = find_token(document.header, "\\language", 0)
3042 if i != -1:
3043 document.header[i] = "\\language english"
3044 j = 0
3045 while True:
3046 j = find_token(document.body, "\\lang mongolian", j)
3047 if j == -1:
3048 return
3049 document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english")
3050 j = j + 1
3053 def revert_default_options(document):
3054 ' Remove param use_default_options '
3055 i = find_token(document.header, "\\use_default_options", 0)
3056 if i != -1:
3057 del document.header[i]
3060 def convert_default_options(document):
3061 ' Add param use_default_options and set it to false '
3062 i = find_token(document.header, "\\textclass", 0)
3063 if i == -1:
3064 document.warning("Malformed LyX document: Missing `\\textclass'.")
3065 return
3066 document.header.insert(i, '\\use_default_options false')
3069 def revert_backref_options(document):
3070 ' Revert option pdf_backref=page to pagebackref '
3071 i = find_token(document.header, "\\pdf_backref page", 0)
3072 if i != -1:
3073 document.header[i] = "\\pdf_pagebackref true"
3076 def convert_backref_options(document):
3077 ' We have changed the option pagebackref to backref=true '
3078 i = find_token(document.header, "\\pdf_pagebackref true", 0)
3079 if i != -1:
3080 document.header[i] = "\\pdf_backref page"
3081 j = find_token(document.header, "\\pdf_pagebackref false", 0)
3082 if j != -1:
3083 del document.header[j]
3084 # backref=true was not a valid option, we meant backref=section
3085 k = find_token(document.header, "\\pdf_backref true", 0)
3086 if k != -1 and i != -1:
3087 del document.header[k]
3088 elif k != -1 and j != -1:
3089 document.header[k] = "\\pdf_backref section"
3092 def convert_charstyle_element(document):
3093 "Convert CharStyle to Element for docbook backend"
3094 if document.backend != "docbook":
3095 return
3096 i = 0
3097 while True:
3098 i = find_token(document.body, "\\begin_inset Flex CharStyle:", i)
3099 if i == -1:
3100 return
3101 document.body[i] = document.body[i].replace('\\begin_inset Flex CharStyle:',
3102 '\\begin_inset Flex Element:')
3104 def revert_charstyle_element(document):
3105 "Convert Element to CharStyle for docbook backend"
3106 if document.backend != "docbook":
3107 return
3108 i = 0
3109 while True:
3110 i = find_token(document.body, "\\begin_inset Flex Element:", i)
3111 if i == -1:
3112 return
3113 document.body[i] = document.body[i].replace('\\begin_inset Flex Element:',
3114 '\\begin_inset Flex CharStyle:')
3117 # Conversion hub
3120 supported_versions = ["1.6.0","1.6"]
3121 convert = [[277, [fix_wrong_tables]],
3122 [278, [close_begin_deeper]],
3123 [279, [long_charstyle_names]],
3124 [280, [axe_show_label]],
3125 [281, []],
3126 [282, []],
3127 [283, [convert_flex]],
3128 [284, []],
3129 [285, []],
3130 [286, []],
3131 [287, [convert_wrapfig_options]],
3132 [288, [convert_inset_command]],
3133 [289, [convert_latexcommand_index]],
3134 [290, []],
3135 [291, []],
3136 [292, [convert_japanese_cjk]],
3137 [293, []],
3138 [294, [convert_pdf_options]],
3139 [295, [convert_htmlurl, convert_url]],
3140 [296, [convert_include]],
3141 [297, [convert_usorbian]],
3142 [298, [convert_macro_global]],
3143 [299, []],
3144 [300, []],
3145 [301, []],
3146 [302, []],
3147 [303, [convert_serbocroatian]],
3148 [304, [convert_framed_notes]],
3149 [305, []],
3150 [306, []],
3151 [307, []],
3152 [308, []],
3153 [309, []],
3154 [310, []],
3155 [311, [convert_ams_classes]],
3156 [312, []],
3157 [313, [convert_module_names]],
3158 [314, []],
3159 [315, []],
3160 [316, [convert_subfig]],
3161 [317, []],
3162 [318, []],
3163 [319, [convert_spaceinset, convert_hfill]],
3164 [320, []],
3165 [321, [convert_tablines]],
3166 [322, [convert_plain_layout]],
3167 [323, [convert_pagebreaks]],
3168 [324, [convert_linebreaks]],
3169 [325, [convert_japanese_plain]],
3170 [326, []],
3171 [327, []],
3172 [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
3173 [329, []],
3174 [330, []],
3175 [331, [convert_ltcaption]],
3176 [332, []],
3177 [333, [update_apa_styles]],
3178 [334, [convert_paper_sizes]],
3179 [335, [convert_InsetSpace]],
3180 [336, []],
3181 [337, [convert_display_enum]],
3182 [338, []],
3183 [339, []],
3184 [340, [add_plain_layout]],
3185 [341, []],
3186 [342, []],
3187 [343, [convert_default_options]],
3188 [344, [convert_backref_options]],
3189 [345, [convert_charstyle_element]]
3192 revert = [[344, [revert_charstyle_element]],
3193 [343, [revert_backref_options]],
3194 [342, [revert_default_options]],
3195 [341, [revert_mongolian]],
3196 [340, [revert_tabulators, revert_tabsize]],
3197 [339, []],
3198 [338, [revert_removed_modules]],
3199 [337, [revert_polytonicgreek]],
3200 [336, [revert_display_enum]],
3201 [335, [remove_fontsCJK]],
3202 [334, [revert_InsetSpace]],
3203 [333, [revert_paper_sizes]],
3204 [332, []],
3205 [331, [revert_graphics_group]],
3206 [330, [revert_ltcaption]],
3207 [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
3208 [328, [revert_master]],
3209 [327, []],
3210 [326, [revert_mexican]],
3211 [325, [revert_pdfpages]],
3212 [324, []],
3213 [323, [revert_linebreaks]],
3214 [322, [revert_pagebreaks]],
3215 [321, [revert_local_layout, revert_plain_layout]],
3216 [320, [revert_tablines]],
3217 [319, [revert_protected_hfill]],
3218 [318, [revert_spaceinset, revert_hfills, revert_hspace]],
3219 [317, [remove_extra_embedded_files]],
3220 [316, [revert_wrapplacement]],
3221 [315, [revert_subfig]],
3222 [314, [revert_colsep, revert_plainlayout]],
3223 [313, []],
3224 [312, [revert_module_names]],
3225 [311, [revert_rotfloat, revert_widesideways]],
3226 [310, [revert_external_embedding]],
3227 [309, [revert_btprintall]],
3228 [308, [revert_nocite]],
3229 [307, [revert_serbianlatin]],
3230 [306, [revert_slash, revert_nobreakdash]],
3231 [305, [revert_interlingua]],
3232 [304, [revert_bahasam]],
3233 [303, [revert_framed_notes]],
3234 [302, []],
3235 [301, [revert_latin, revert_samin]],
3236 [300, [revert_linebreak]],
3237 [299, [revert_pagebreak]],
3238 [298, [revert_hyperlinktype]],
3239 [297, [revert_macro_optional_params]],
3240 [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3241 [295, [revert_include]],
3242 [294, [revert_href, revert_url]],
3243 [293, [revert_pdf_options_2]],
3244 [292, [revert_inset_info]],
3245 [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3246 [290, [revert_vietnamese]],
3247 [289, [revert_wraptable]],
3248 [288, [revert_latexcommand_index]],
3249 [287, [revert_inset_command]],
3250 [286, [revert_wrapfig_options]],
3251 [285, [revert_pdf_options]],
3252 [284, [remove_inzip_options]],
3253 [283, []],
3254 [282, [revert_flex]],
3255 [281, []],
3256 [280, [revert_begin_modules]],
3257 [279, [revert_show_label]],
3258 [278, [revert_long_charstyle_names]],
3259 [277, []],
3260 [276, []]
3264 if __name__ == "__main__":
3265 pass