X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=lib%2Flyx2lyx%2Flyx_1_6.py;h=3b98896ac628c12d7b6c545b392a95a0400810da;hb=d45ca67d1d3e2d4fdc344cd2a1517725bc91723a;hp=8edcbed9643a5efc7bdc2739e234441fab58ae7e;hpb=10f7b8cb3556cbef68481fbcc30f86e88926f3e5;p=lyx.git diff --git a/lib/lyx2lyx/lyx_1_6.py b/lib/lyx2lyx/lyx_1_6.py index 8edcbed964..3b98896ac6 100644 --- a/lib/lyx2lyx/lyx_1_6.py +++ b/lib/lyx2lyx/lyx_1_6.py @@ -43,10 +43,18 @@ def find_end_of_inset(lines, i): # where the last statement resets the counter to accord with the added # lines. def wrap_into_ert(string, src, dst): - " Wrap a something into an ERT" + '''Within string, replace occurrences of src with dst, wrapped into ERT + E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is: + sch\\backslash"on''' return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n' + dst + '\n\\end_layout\n\\end_inset\n') +def put_cmd_in_ert(string): + string = string.replace('\\', "\\backslash\n") + string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n" \ + + string + "\n\\end_layout\n\\end_inset" + return string + def add_to_preamble(document, text): """ Add text to the preamble if it is not already there. Only the first line is checked!""" @@ -56,6 +64,11 @@ def add_to_preamble(document, text): document.preamble.extend(text) +def insert_to_preamble(index, document, text): + """ Insert text to the preamble at a given line""" + + document.preamble.insert(index, text) + # Convert a LyX length into a LaTeX length def convert_len(len): units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth", @@ -114,6 +127,265 @@ def set_option(document, m, option, value): return l +def read_unicodesymbols(): + " Read the unicodesymbols list of unicode characters and corresponding commands." + pathname = os.path.abspath(os.path.dirname(sys.argv[0])) + fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols')) + spec_chars = [] + # Two backslashes, followed by some non-word character, and then a character + # in brackets. The idea is to check for constructs like: \"{u}, which is how + # they are written in the unicodesymbols file; but they can also be written + # as: \"u. + r = re.compile(r'\\\\(\W)\{(\w)\}') + for line in fp.readlines(): + if line[0] != '#' and line.strip() != "": + line=line.replace(' "',' ') # remove all quotation marks with spaces before + line=line.replace('" ',' ') # remove all quotation marks with spaces after + line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis) + try: + [ucs4,command,dead] = line.split(None,2) + if command[0:1] != "\\": + continue + spec_chars.append([command, unichr(eval(ucs4))]) + except: + continue + m = r.match(command) + if m != None: + command = "\\\\" + # If the character is a double-quote, then we need to escape it, too, + # since it is done that way in the LyX file. + if m.group(1) == "\"": + command += "\\" + command += m.group(1) + m.group(2) + spec_chars.append([command, unichr(eval(ucs4))]) + fp.close() + return spec_chars + + +def extract_argument(line): + 'Extracts a LaTeX argument from the start of line. Returns (arg, rest).' + + if not line: + return (None, "") + + bracere = re.compile("(\s*)(.*)") + n = bracere.match(line) + whitespace = n.group(1) + stuff = n.group(2) + brace = stuff[:1] + if brace != "[" and brace != "{": + return (None, line) + + # find closing brace + remain = stuff[1:] + pos = 0 + num = 1 + term = "}" + if brace == "[": + term = "]" + skip = False + for c in remain: + if skip: + skip = False + elif c == "\\": + skip = True + elif c == brace: + num += 1 + elif c == term: + num -= 1 + if c == 0: + break + pos += 1 + if num != 0: + # We never found the matching brace + # So, to be on the safe side, let's just return everything + # which will then get wrapped as ERT + return (line, "") + return (line[:pos + 1], line[pos + 1:]) + + +def latex2ert(line): + '''Converts LaTeX commands into ERT. line may well be a multi-line + string when it is returned.''' + if not line: + return line + + retval = "" + ## FIXME Escaped \ ?? + # This regex looks for a LaTeX command---i.e., something of the form + # "\alPhaStuFF", or "\X", where X is any character---where the command + # may also be preceded by an additional backslash, which is how it would + # appear (e.g.) in an InsetIndex. + labelre = re.compile(r'(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)') + + m = labelre.match(line) + while m != None: + retval += m.group(1) + cmd = m.group(2) + end = m.group(3) + + while True: + (arg, rest) = extract_argument(end) + if arg == None: + break + cmd += arg + end = rest + # If we wanted to put labels into an InsetLabel, for example, then we + # would just need to test here for cmd == "label" and then take some + # appropriate action, i.e., to use arg to get the content and then + # wrap it appropriately. + cmd = put_cmd_in_ert(cmd) + retval += "\n" + cmd + "\n" + line = end + m = labelre.match(line) + retval += line + return retval + + +#Bug 5022.... +#Might should do latex2ert first, then deal with stuff that DOESN'T +#end up inside ERT. That routine could be modified so that it returned +#a list of lines, and we could then skip ERT bits and only deal with +#the other bits. +def latex2lyx(data): + '''Takes a string, possibly multi-line, and returns the result of + converting LaTeX constructs into LyX constructs. Returns a list of + lines, suitable for insertion into document.body.''' + + retval = [] + + # Convert LaTeX to Unicode + reps = read_unicodesymbols() + # Commands of this sort need to be checked to make sure they are + # followed by a non-alpha character, lest we replace too much. + hardone = re.compile(r'^\\\\[a-zA-Z]+$') + + for rep in reps: + if hardone.match(rep[0]): + pos = 0 + while True: + pos = data.find(rep[0], pos) + if pos == -1: + break + nextpos = pos + len(rep[0]) + if nextpos < len(data) and data[nextpos].isalpha(): + # not the end of that command + pos = nextpos + continue + data = data[:pos] + rep[1] + data[nextpos:] + pos = nextpos + else: + data = data.replace(rep[0], rep[1]) + + # Generic, \" -> ": + data = wrap_into_ert(data, r'\"', '"') + + # Math: + mathre = re.compile('^(.*?)(\$.*?\$)(.*)') + lines = data.split('\n') + for line in lines: + #document.warning("LINE: " + line) + #document.warning(str(i) + ":" + document.body[i]) + #document.warning("LAST: " + document.body[-1]) + g = line + m = mathre.match(g) + while m != None: + s = m.group(1) + f = m.group(2).replace('\\\\', '\\') + g = m.group(3) + if s: + # this is non-math! + s = latex2ert(s) + subst = s.split('\n') + retval += subst + retval.append("\\begin_inset Formula " + f) + retval.append("\\end_inset") + m = mathre.match(g) + # Handle whatever is left, which is just text + g = latex2ert(g) + subst = g.split('\n') + retval += subst + return retval + + +def lyx2latex(document, lines): + 'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.' + # clean up multiline stuff + content = "" + ert_end = 0 + reps = read_unicodesymbols() + + for curline in range(len(lines)): + line = lines[curline] + if line.startswith("\\begin_inset ERT"): + # We don't want to replace things inside ERT, so figure out + # where the end of the inset is. + ert_end = find_end_of_inset(lines, curline + 1) + continue + elif line.startswith("\\begin_inset Formula"): + line = line[20:] + elif line.startswith("\\begin_inset Quotes"): + # For now, we do a very basic reversion. Someone who understands + # quotes is welcome to fix it up. + qtype = line[20:].strip() + # lang = qtype[0] + side = qtype[1] + dbls = qtype[2] + if side == "l": + if dbls == "d": + line = "``" + else: + line = "`" + else: + if dbls == "d": + line = "''" + else: + line = "'" + elif line.isspace() or \ + line.startswith("\\begin_layout") or \ + line.startswith("\\end_layout") or \ + line.startswith("\\begin_inset") or \ + line.startswith("\\end_inset") or \ + line.startswith("\\lang") or \ + line.strip() == "status collapsed" or \ + line.strip() == "status open": + #skip all that stuff + continue + + # this needs to be added to the preamble because of cases like + # \textmu, \textbackslash, etc. + add_to_preamble(document, ['% added by lyx2lyx for converted index entries', + '\\@ifundefined{textmu}', + ' {\\usepackage{textcomp}}{}']) + # a lossless reversion is not possible + # try at least to handle some common insets and settings + if ert_end >= curline: + line = line.replace(r'\backslash', r'\\') + else: + line = line.replace('&', '\\&{}') + line = line.replace('#', '\\#{}') + line = line.replace('^', '\\^{}') + line = line.replace('%', '\\%{}') + line = line.replace('_', '\\_{}') + line = line.replace('$', '\\${}') + + # Do the LyX text --> LaTeX conversion + for rep in reps: + line = line.replace(rep[1], rep[0] + "{}") + line = line.replace(r'\backslash', r'\textbackslash{}') + line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}') + line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}') + line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}') + line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}') + line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}') + line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}') + line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}') + line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}') + line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'') + content += line + return content + + #################################################################### def convert_ltcaption(document): @@ -412,7 +684,7 @@ def revert_long_charstyle_names(document): i = find_token(document.body, "\\begin_inset CharStyle", i) if i == -1: return - document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle") + document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ") i += 1 @@ -621,9 +893,12 @@ def revert_pdf_options(document): setupstart = "" setupend = "" # write the preamble - add_to_preamble(document, - ['% Commands inserted by lyx2lyx for PDF properties', - '\\usepackage[unicode=true' + # babel must be loaded before hyperref and hyperref the first part + # of the preamble, like in LyX 1.6 + insert_to_preamble(0, document, + '% Commands inserted by lyx2lyx for PDF properties\n' + + '\\usepackage{babel}\n' + + '\\usepackage[unicode=true' + bookmarks + breaklinks + pdfborder @@ -632,14 +907,14 @@ def revert_pdf_options(document): + colorlinks + pagemode + ']\n' - ' {hyperref}\n' + + ' {hyperref}\n' + setupstart + title + author + subject + keywords + otheroptions - + setupend]) + + setupend) def remove_inzip_options(document): @@ -748,89 +1023,65 @@ def revert_wrapfig_options(document): "Revert optional options for wrap floats (wrapfig)." i = 0 while True: - i = find_token(document.body, "lines", i) + i = find_token(document.body, "\\begin_inset Wrap figure", i) if i == -1: return - j = find_token(document.body, "overhang", i+1) - if j != i + 2 and j != -1: - document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float.") + j = find_end_of_inset(document.body, i) if j == -1: - return - del document.body[i] - del document.body[j-1] - i = i + 1 - + document.warning("Can't find end of Wrap inset at line " + str(i)) + i += 1 + continue + k = find_default_layout(document, i, j) + if k == -1: + document.warning("Can't find default layout for Wrap figure!") + i = j + continue + # Options should be between i and k now + l = find_token(document.body, "lines", i, k) + if l == -1: + document.warning("Can't find lines option for Wrap figure!") + i = k + continue + m = find_token(document.body, "overhang", i + 1, k) + if m == -1: + document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!") + i = k + continue + # Do these in reverse order + del document.body[m] + del document.body[l] + i = k -# To convert and revert indices, we need to convert between LaTeX -# strings and LyXText. Here we do a minimal conversion to prevent -# crashes and data loss. Manual patch-up may be needed. -replacements = [ - [r'\\\"a', u'ä'], - [r'\\\"o', u'ö'], - [r'\\\"u', u'ü'], - [r'\\\'a', u'á'], - [r'\\\'e', u'é'], - [r'\\\'i', u'í'], - [r'\\\'o', u'ó'], - [r'\\\'u', u'ú'] -] def convert_latexcommand_index(document): "Convert from LatexCommand form to collapsable form." i = 0 + r1 = re.compile('name "(.*)"') while True: i = find_token(document.body, "\\begin_inset CommandInset index", i) if i == -1: return if document.body[i + 1] != "LatexCommand index": # Might also be index_print return - fullcontent = document.body[i + 2][5:] - fullcontent.strip() - fullcontent = fullcontent[1:-1] - document.body[i:i + 3] = ["\\begin_inset Index", - "status collapsed", - "\\begin_layout Standard"] - i += 3 - # We are now on the blank line preceding "\end_inset" - # We will write the content here, into the inset. - - # Do the LaTeX --> LyX text conversion - for rep in replacements: - fullcontent = fullcontent.replace(rep[0], rep[1]) - # Generic, \" -> ": - fullcontent = wrap_into_ert(fullcontent, r'\"', '"') - # Math: - r = re.compile('^(.*?)(\$.*?\$)(.*)') - lines = fullcontent.split('\n') - for line in lines: - #document.warning("LINE: " + line) - #document.warning(str(i) + ":" + document.body[i]) - #document.warning("LAST: " + document.body[-1]) - g = line - while r.match(g): - m = r.match(g) - s = m.group(1) - f = m.group(2).replace('\\\\', '\\') - g = m.group(3) - if s: - # this is non-math! - s = wrap_into_ert(s, r'\\', '\\backslash') - s = wrap_into_ert(s, '{', '{') - s = wrap_into_ert(s, '}', '}') - subst = s.split('\n') - document.body[i:i] = subst - i += len(subst) - document.body.insert(i + 1, "\\begin_inset Formula " + f) - document.body.insert(i + 2, "\\end_inset") + j = find_end_of_inset(document.body, i + 2) + if j == -1: + document.warning("Unable to find end of index inset at line " + i + "!") i += 2 - # Generic, \\ -> \backslash: - g = wrap_into_ert(g, r'\\', '\\backslash') - g = wrap_into_ert(g, '{', '{') - g = wrap_into_ert(g, '}', '}') - subst = g.split('\n') - document.body[i+1:i+1] = subst - i += len(subst) - document.body.insert(i + 1, "\\end_layout") + continue + m = r1.match(document.body[i + 2]) + if m == None: + document.warning("Unable to match: " + document.body[i+2]) + # this can happen with empty index insets! + linelist = [""] + else: + fullcontent = m.group(1) + linelist = latex2lyx(fullcontent) + #document.warning(fullcontent) + + linelist = ["\\begin_inset Index", "status collapsed", "\\begin_layout Standard", ""] + \ + linelist + ["\\end_layout"] + document.body[i : j] = linelist + i += len(linelist) - (j - i) def revert_latexcommand_index(document): @@ -843,58 +1094,13 @@ def revert_latexcommand_index(document): j = find_end_of_inset(document.body, i + 1) if j == -1: return - del document.body[j - 1] - del document.body[j - 2] # \end_layout - document.body[i] = "\\begin_inset CommandInset index" - document.body[i + 1] = "LatexCommand index" - # clean up multiline stuff - content = "" - ert_end = 0 - for k in range(i + 3, j - 2): - line = document.body[k] - if line.startswith("\\begin_inset ERT"): - ert_end = find_end_of_inset(document.body, k + 1) - line = line[16:] - if line.startswith("\\begin_inset Formula"): - line = line[20:] - if line.startswith("\\begin_layout Standard"): - line = line[22:] - if line.startswith("\\begin_layout Plain Layout"): - line = line[26:] - if line.startswith("\\end_layout"): - line = line[11:] - if line.startswith("\\end_inset"): - line = line[10:] - if line.startswith("status collapsed"): - line = line[16:] - if line.startswith("status open"): - line = line[11:] - # a lossless reversion is not possible - # try at least to handle some common insets and settings - # do not replace inside ERTs - if ert_end < k: - # Do the LyX text --> LaTeX conversion - for rep in replacements: - line = line.replace(rep[1], rep[0]) - line = line.replace(r'\backslash', r'\textbackslash{}') - line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}') - line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}') - line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}') - line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}') - line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}') - line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}') - line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}') - line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}') - line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'') - else: - line = line.replace(r'\backslash', r'\\') - content = content + line; - document.body[i + 3] = "name " + '"' + content + '"' - for k in range(i + 4, j - 2): - del document.body[i + 4] - document.body.insert(i + 4, "") - del document.body[i + 2] # \begin_layout standard - i = i + 5 + + content = lyx2latex(document, document.body[i:j]) + # escape quotes + content = content.replace('"', r'\"') + document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index", + "name " + '"' + content + '"', ""] + i += 5 def revert_wraptable(document): @@ -926,6 +1132,24 @@ def revert_vietnamese(document): j = j + 1 +def convert_japanese_cjk(document): + "Set language japanese to japanese-cjk" + # Set document language from japanese-plain to japanese + i = 0 + if document.language == "japanese": + document.language = "japanese-cjk" + i = find_token(document.header, "\\language", 0) + if i != -1: + document.header[i] = "\\language japanese-cjk" + j = 0 + while True: + j = find_token(document.body, "\\lang japanese", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk") + j = j + 1 + + def revert_japanese(document): "Set language japanese-plain to japanese" # Set document language from japanese-plain to japanese @@ -944,6 +1168,24 @@ def revert_japanese(document): j = j + 1 +def revert_japanese_cjk(document): + "Set language japanese-cjk to japanese" + # Set document language from japanese-plain to japanese + i = 0 + if document.language == "japanese-cjk": + document.language = "japanese" + i = find_token(document.header, "\\language", 0) + if i != -1: + document.header[i] = "\\language japanese" + j = 0 + while True: + j = find_token(document.body, "\\lang japanese-cjk", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese") + j = j + 1 + + def revert_japanese_encoding(document): "Set input encoding form EUC-JP-plain to EUC-JP etc." # Set input encoding form EUC-JP-plain to EUC-JP etc. @@ -1096,7 +1338,8 @@ def convert_ams_classes(document): return m = r.match(document.body[i]) if m == None: - document.warning("Weirdly formed \\begin_layout at line %d of body!" % i) + # This is an empty layout + # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i) i += 1 continue m = m.group(1) @@ -1117,35 +1360,34 @@ def revert_href(document): i = i + 2 def revert_url(document): - 'Reverts Flex URL insets to old-style URL insets' - i = 0 - while True: - i = find_token(document.body, "\\begin_inset Flex URL", i) - if i == -1: - return - j = find_end_of_inset(document.body, i) - if j == -1: - document.warning("Can't find end of inset in revert_url!") - return - k = find_default_layout(document, i, j) - if k == -1: - document.warning("Can't find default layout in revert_url!") - i = j - continue - l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout") - if l == -1 or l >= j: - document.warning("Can't find end of default layout in revert_url!") - i = j - continue - # OK, so the inset's data is between lines k and l. - data = " ".join(document.body[k+1:l]) - data = data.strip() - newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\ - "", "\\end_inset"] - document.body[i:j+1] = newinset - i = i + len(newinset) - - + 'Reverts Flex URL insets to old-style URL insets' + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Flex URL", i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Can't find end of inset in revert_url!") + return + k = find_default_layout(document, i, j) + if k == -1: + document.warning("Can't find default layout in revert_url!") + i = j + continue + l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout") + if l == -1 or l >= j: + document.warning("Can't find end of default layout in revert_url!") + i = j + continue + # OK, so the inset's data is between lines k and l. + data = " ".join(document.body[k+1:l]) + data = data.strip() + newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\ + "", "\\end_inset"] + document.body[i:j+1] = newinset + i = i + len(newinset) + def convert_include(document): 'Converts include insets to new format.' @@ -1179,40 +1421,50 @@ def convert_include(document): def revert_include(document): 'Reverts include insets to old format.' i = 0 + r0 = re.compile('preview.*') r1 = re.compile('LatexCommand (.+)') - r2 = re.compile('filename (.+)') - r3 = re.compile('options (.*)') + r2 = re.compile('filename "(.+)"') + r3 = re.compile('lstparams "(.*)"') while True: i = find_token(document.body, "\\begin_inset CommandInset include", i) if i == -1: return - previewline = document.body[i + 1] - m = r1.match(document.body[i + 2]) + nextline = i + 1 + m = r1.match(document.body[nextline]) if m == None: document.warning("Malformed LyX document: No LatexCommand line for `" + document.body[i] + "' on line " + str(i) + ".") i += 1 continue cmd = m.group(1) - m = r2.match(document.body[i + 3]) + nextline += 1 + if r0.match(document.body[nextline]): + previewline = document.body[nextline] + nextline += 1 + else: + previewline = "" + m = r2.match(document.body[nextline]) if m == None: document.warning("Malformed LyX document: No filename line for `" + \ document.body[i] + "' on line " + str(i) + ".") i += 2 continue fn = m.group(1) + nextline += 1 options = "" - numlines = 4 if (cmd == "lstinputlisting"): - m = r3.match(document.body[i + 4]) + m = r3.match(document.body[nextline]) if m != None: options = m.group(1) numlines = 5 + nextline += 1 newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}" if options: newline += ("[" + options + "]") - insertion = [newline, previewline] - document.body[i : i + numlines] = insertion + insertion = [newline] + if previewline != "": + insertion.append(previewline) + document.body[i : nextline] = insertion i += 2 @@ -1394,7 +1646,7 @@ def convert_framed_notes(document): 'position "t"', 'hor_pos "c"', 'has_inner_box 0', - 'inner_pos "t"', + 'inner_pos "t"', 'use_parbox 0', 'width "100col%"', 'special "none"', @@ -1550,7 +1802,7 @@ def revert_nobreakdash(document): #Returns number of lines added/removed def revert_nocite_key(body, start, end): - 'key "..." -> \nocite{...}' + 'key "..." -> \nocite{...}' r = re.compile(r'^key "(.*)"') i = start j = end @@ -1720,17 +1972,17 @@ def revert_rotfloat(document): subst = ['\\begin_layout Standard', '\\begin_inset ERT', 'status collapsed', '', - '\\begin_layout Standard', '', '', + '\\begin_layout Standard', '', '', '\\backslash', '', 'end{sideways' + floattype + '}', '\\end_layout', '', '\\end_inset'] document.body[j : j+1] = subst addedLines = len(subst) - 1 del document.body[i+1 : l] - addedLines -= (l-1) - (i+1) + addedLines -= (l-1) - (i+1) subst = ['\\begin_inset ERT', 'status collapsed', '', - '\\begin_layout Standard', '', '', '\\backslash', - 'begin{sideways' + floattype + '}', + '\\begin_layout Standard', '', '', '\\backslash', + 'begin{sideways' + floattype + '}', '\\end_layout', '', '\\end_inset', '', '\\end_layout', ''] document.body[i : i+1] = subst @@ -1779,10 +2031,10 @@ def revert_widesideways(document): if l == -1: document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.") return - subst = ['\\begin_layout Standard', '\\begin_inset ERT', - 'status collapsed', '', + subst = ['\\begin_layout Standard', '\\begin_inset ERT', + 'status collapsed', '', '\\begin_layout Standard', '', '', '\\backslash', - 'end{sideways' + floattype + '*}', + 'end{sideways' + floattype + '*}', '\\end_layout', '', '\\end_inset'] document.body[j : j+1] = subst addedLines = len(subst) - 1 @@ -1823,7 +2075,6 @@ def revert_external_embedding(document): revert_inset_embedding(document, 'External') -# FIXME This code can still be cleaned up a fair bit. def convert_subfig(document): " Convert subfigures to subfloats. " i = 0 @@ -1838,28 +2089,28 @@ def convert_subfig(document): continue k = find_token(document.body, '\tsubcaption', i, endInset) if k == -1: - i += 1 + i = endInset continue l = find_token(document.body, '\tsubcaptionText', i, endInset) + if l == -1: + document.warning("Malformed lyx document: Can't find subcaptionText!") + i = endInset + continue caption = document.body[l][16:].strip('"') - savestr = document.body[i] - laststr = document.body[endInset] del document.body[l] del document.body[k] addedLines = -2 - # savestr should no longer be needed here. - subst = ['\\begin_inset Float figure', 'wide false', 'sideways false', - 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption', - '', '\\begin_layout Plain Layout', - caption, '\\end_layout', '', '\\end_inset', '', - '\\end_layout', '', '\\begin_layout Plain Layout', savestr] - document.body[i : i+1] = subst - addedLines += len(subst) - 1 + subst = ['\\begin_inset Float figure', 'wide false', 'sideways false', + 'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption', + '', '\\begin_layout Plain Layout'] + latex2lyx(caption) + \ + [ '\\end_layout', '', '\\end_inset', '', + '\\end_layout', '', '\\begin_layout Plain Layout'] + document.body[i : i] = subst + addedLines += len(subst) endInset += addedLines - # There should be an easier way to do this. - subst = ['', '\\end_inset', '', '\\end_layout', laststr] - document.body[endInset : endInset+1] = subst - addedLines += len(subst) - 1 + subst = ['', '\\end_inset', '', '\\end_layout'] + document.body[endInset : endInset] = subst + addedLines += len(subst) i += addedLines + 1 @@ -1968,8 +2219,7 @@ def revert_subfig(document): insertion = insertion.split('\n') document.body[k : k + 1] = insertion addedLines += len(insertion) - 1 - add_to_preamble(document, - ['\\usepackage{subfig}\n']) + add_to_preamble(document, ['\\usepackage{subfig}\n']) i += addedLines + 1 @@ -1977,18 +2227,21 @@ def revert_wrapplacement(document): " Revert placement options wrap floats (wrapfig). " i = 0 while True: - i = find_token(document.body, "lines", i) + i = find_token(document.body, "\\begin_inset Wrap figure", i) if i == -1: return - j = find_token(document.body, "placement", i+1) - if j != i + 1: + e = find_end_of_inset(document.body, i) + j = find_token(document.body, "placement", i + 1, e) + if j == -1: document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.") - return - document.body[j] = document.body[j].replace("placement O", "placement o") - document.body[j] = document.body[j].replace("placement I", "placement i") - document.body[j] = document.body[j].replace("placement L", "placement l") - document.body[j] = document.body[j].replace("placement R", "placement r") - i = i + 1 + i += 1 + continue + r = re.compile("placement (o|i|l|r)") + m = r.match(document.body[j]) + if m == None: + document.warning("Malformed LyX document: Placement option isn't O|I|R|L!") + document.body[j] = "placement " + m.group(1).lower() + i = j def remove_extra_embedded_files(document): @@ -2576,7 +2829,7 @@ def remove_fontsCJK(document): def convert_plain_layout(document): - " Convert 'PlainLayout' to 'Plain Layout'" + " Convert 'PlainLayout' to 'Plain Layout'" i = 0 while True: i = find_token(document.body, '\\begin_layout PlainLayout', i) @@ -2588,7 +2841,7 @@ def convert_plain_layout(document): def revert_plain_layout(document): - " Convert 'PlainLayout' to 'Plain Layout'" + " Convert 'PlainLayout' to 'Plain Layout'" i = 0 while True: i = find_token(document.body, '\\begin_layout Plain Layout', i) @@ -2600,7 +2853,7 @@ def revert_plain_layout(document): def revert_plainlayout(document): - " Convert 'PlainLayout' to 'Plain Layout'" + " Convert 'PlainLayout' to 'Plain Layout'" i = 0 while True: i = find_token(document.body, '\\begin_layout PlainLayout', i) @@ -2631,6 +2884,93 @@ def revert_polytonicgreek(document): j = j + 1 +def revert_removed_modules(document): + i = 0 + while True: + i = find_token(document.header, "\\begin_remove_modules", i) + if i == -1: + return + j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules") + if j == -1: + # this should not happen + break + document.header[i : j + 1] = [] + + +def add_plain_layout(document): + i = 0 + while True: + i = find_token(document.body, "\\begin_layout", i) + if i == -1: + return + if len(document.body[i].split()) == 1: + document.body[i] = "\\begin_layout Plain Layout" + i += 1 + + +def revert_tabulators(document): + "Revert tabulators to 4 spaces" + i = 0 + while True: + i = find_token(document.body, "\t", i) + if i == -1: + return + document.body[i] = document.body[i].replace("\t", " ") + i += 1 + + +def revert_tabsize(document): + "Revert the tabsize parameter of listings" + i = 0 + j = 0 + while True: + # either it is the only parameter + i = find_token(document.body, 'lstparams "tabsize=4"', i) + if i != -1: + del document.body[i] + # or the last one + j = find_token(document.body, "lstparams", j) + if j == -1: + return + pos = document.body[j].find(",tabsize=") + document.body[j] = document.body[j][:pos] + '"' + i += 1 + j += 1 + + +def revert_mongolian(document): + "Set language Mongolian to English" + i = 0 + if document.language == "mongolian": + document.language = "english" + i = find_token(document.header, "\\language", 0) + if i != -1: + document.header[i] = "\\language english" + j = 0 + while True: + j = find_token(document.body, "\\lang mongolian", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang mongolian", "\\lang english") + j = j + 1 + + +def revert_default_options(document): + ' Remove param use_default_options ' + i = find_token(document.header, "\\use_default_options", 0) + if i != -1: + del document.header[i] + + +def convert_default_options(document): + ' Add param use_default_options and set it to false ' + i = find_token(document.header, "\\textclass", 0) + if i == -1: + document.warning("Malformed LyX document: Missing `\\textclass'.") + return + document.header.insert(i, '\\use_default_options false') + + ## # Conversion hub # @@ -2651,7 +2991,7 @@ convert = [[277, [fix_wrong_tables]], [289, [convert_latexcommand_index]], [290, []], [291, []], - [292, []], + [292, [convert_japanese_cjk]], [293, []], [294, [convert_pdf_options]], [295, [convert_htmlurl, convert_url]], @@ -2698,9 +3038,19 @@ convert = [[277, [fix_wrong_tables]], [336, []], [337, [convert_display_enum]], [338, []], + [339, []], + [340, [add_plain_layout]], + [341, []], + [342, []], + [343, [convert_default_options]] ] -revert = [[337, [revert_polytonicgreek]], +revert = [[342, [revert_default_options]], + [341, [revert_mongolian]], + [340, [revert_tabulators, revert_tabsize]], + [339, []], + [338, [revert_removed_modules]], + [337, [revert_polytonicgreek]], [336, [revert_display_enum]], [335, [remove_fontsCJK]], [334, [revert_InsetSpace]], @@ -2746,7 +3096,7 @@ revert = [[337, [revert_polytonicgreek]], [294, [revert_href, revert_url]], [293, [revert_pdf_options_2]], [292, [revert_inset_info]], - [291, [revert_japanese, revert_japanese_encoding]], + [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]], [290, [revert_vietnamese]], [289, [revert_wraptable]], [288, [revert_latexcommand_index]],