From: José Matox Date: Wed, 14 Apr 2004 08:45:46 +0000 (+0000) Subject: The big lyx2lyx rewrite. X-Git-Tag: 1.6.10~15313 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=bc7f66b2b73ca205423d1d19025c6a3f858dcee3;p=lyx.git The big lyx2lyx rewrite. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8653 a592a061-630c-0410-9148-cb99ea01b6c8 --- diff --git a/lib/lyx2lyx/ChangeLog b/lib/lyx2lyx/ChangeLog index a3d7ace5a0..46b9183bd9 100644 --- a/lib/lyx2lyx/ChangeLog +++ b/lib/lyx2lyx/ChangeLog @@ -1,3 +1,12 @@ +2004-03-31 Georg Baum + + * lyxconvert_229.py (convert_jurabib): new, add use_jurabib flag + * lyxrevert_230.py (convert_jurabib): new, remove use_jurabib flag + * lyxconvert_230.py (convert_float): new, add sideways flag + * lyxrevert_231.py (convert_float): new, remove sideways flag + * lyxconvert_231.py (convert_bibtopic): new, add use_bibtopic flag + * lyxrevert_232.py (convert_bibtopic): new, remove use_bibtopic flag + 2004-03-29 Jürgen Spitzmüller * lyx2lyx: up the format to 232. diff --git a/lib/lyx2lyx/error.py b/lib/lyx2lyx/error.py deleted file mode 100644 index 79eec9fa3a..0000000000 --- a/lib/lyx2lyx/error.py +++ /dev/null @@ -1,30 +0,0 @@ -# This file is part of lyx2lyx -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2002-2003 José Matos -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -class Error: - invalid_file = "Invalid LyX file\n" - invalid_format = "Invalid LyX format\n" - format_not_supported = "Format not supported\n" - same_format = "No convertion because start and ending formats are the same\n" - newer_format = "Starting format is newer than end format\n" - -class Warning: - dont_match = "Proposed and input file formats do not match" - -error = Error() -warning = Warning() diff --git a/lib/lyx2lyx/lyx2lyx b/lib/lyx2lyx/lyx2lyx index 535ba1d97e..b96af09b11 100755 --- a/lib/lyx2lyx/lyx2lyx +++ b/lib/lyx2lyx/lyx2lyx @@ -1,6 +1,6 @@ #! /usr/bin/env python # -*- coding: iso-8859-1 -*- -# Copyright (C) 2002-2003 José Matos +# Copyright (C) 2002-2004 José Matos # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -16,32 +16,31 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -import getopt, sys, string, re -from error import error, warning -from parser_tools import set_comment, set_format, check_token +import getopt import gzip - -version = "1.4.0cvs" +import sys +from parser_tools import read_file, write_file, read_version, set_version, \ + read_format, set_format, chain, lyxformat, get_value # Allow the dummy object to be able to carry related data # like a C struct class struct: - pass - -# options object, with default values -opt = struct() - -opt.output = sys.stdout -opt.input = sys.stdin -opt.err = sys.stderr -opt.start = None -opt.end = None -opt.quiet = 0 - -format = re.compile(r"(\d)[\.,]?(\d\d)") -fileformat = re.compile(r"\\lyxformat\s*(\S*)") -lst_ft = [210, 215, 216, 217, 218, 220, 221, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232] + def __init__(self): + self.output = sys.stdout + self.input = sys.stdin + self.err = sys.stderr + self.debug = 1 + self.start = None + self.end = None + + def warning(self, message, debug_level= 10): + if debug_level <= self.debug: + self.err.write(message + "\n") + + def error(self, message): + self.warning(message) + self.warning("Quiting.") + sys.exit(1) def usage(): print """Usage: lyx2lyx [options] [file] @@ -52,7 +51,7 @@ Options: -h, --help this information -v, --version output version information and exit -l, --list list all available formats - -d, --debug level level=0..2 (O_ no debug information,2_verbose) + -d, --debug level level=0..2 (O_ no debug information, 2_verbose) default: level=1 -e, --err error_file name of the error file or else goes to stderr -f, --from version initial version (optional) @@ -61,7 +60,7 @@ Options: -q, --quiet same as --debug=0""" -def parse_options(argv): +def parse_options(argv, version, opt): _options = ["help", "version", "list", "debug=", "err=", "from=", "to=", "output=", "quiet"] try: opts, args = getopt.getopt(argv[1:], "d:e:f:hlo:qt:v", _options) @@ -74,28 +73,25 @@ def parse_options(argv): usage() sys.exit() if o in ("-v", "--version"): - print "lyxconvert, version %s" %(version) - print "Copyright (C) 2002-2003 José Matos and Dekel Tsur" + print "lyx2lyx, version %s" %(version) + print "Copyright (C) 2002-2004 José Matos and Dekel Tsur" sys.exit() if o in ("-d", "--debug"): opt.debug = int(a) if o in ("-q", "--quiet"): opt.debug = 0 if o in ("-l", "--list"): - print lst_ft + # list available formats sys.exit() if o in ("-o", "--output"): opt.output = open(a, "w") if o in ("-f", "--from"): - opt.start = lyxformat(a) + opt.start = lyxformat(a, opt) if o in ("-t", "--to"): - opt.end = lyxformat(a) + opt.end = lyxformat(a, opt) if o in ("-e","--err"): opt.err = open(a, "w") - if not opt.end: - opt.end = lst_ft[len(lst_ft)-1] - if args: file = args[0] try: @@ -105,94 +101,34 @@ def parse_options(argv): except: opt.input = open(file) -def lyxformat(fmt): - result = format.match(fmt) - if result: - fmt = int(result.group(1) + result.group(2)) - else: - opt.err.write(str(fmt) + ": " + error.invalid_format) - sys.exit(2) - - if fmt in lst_ft: - return fmt - - opt.err.write(str(fmt) + ": " + error.format_not_supported) - sys.exit(1) - -def read_file(file, header, body): - """Reads a file into the header and body parts""" - fmt = None - preamble = 0 - - while 1: - line = file.readline() - if not line: - opt.err.write(error.invalid_file) - sys.exit(3) - - line = line[:-1] - if check_token(line, '\\begin_preamble'): - preamble = 1 - if check_token(line, '\\end_preamble'): - preamble = 0 - - if not preamble: - line = string.strip(line) - - if not line and not preamble: - break - - header.append(line) - result = fileformat.match(line) - if result: - fmt = lyxformat(result.group(1)) - - while 1: - line = file.readline() - if not line: - break - body.append(line[:-1]) - - if not fmt: - opt.err.write(error.invalid_file) - sys.exit(3) - return fmt - -def write_file(file, header, body): - for line in header: - file.write(line+"\n") - file.write("\n") - for line in body: - file.write(line+"\n") - def main(argv): - parse_options(argv) + version = "1.4.0cvs" + + # options object, with default values + opt = struct() + + parse_options(argv, version, opt) header, body = [], [] - fmt = read_file(opt.input, header, body) - - if opt.start: - if opt.start != fmt: - opt.err.write("%s: %s %s\n" % (warning.dont_match, opt.start, fmt)) - else: - opt.start = fmt - - # Convertion chain - if opt.start < opt.end: - mode = "lyxconvert_" - else: - lst_ft.reverse() - mode = "lyxrevert_" - - start = lst_ft.index(opt.start) - end = lst_ft.index(opt.end) - - for fmt in lst_ft[start:end]: - __import__(mode + str(fmt)).convert(header,body) - - set_comment(header, version) - set_format(header, opt.end) - write_file(opt.output, header, body) + + read_file(header, body, opt) + + initial_version = read_version(header) + opt.format = read_format(header, opt) + opt.language = get_value(header, "\\language", 0) + if opt.language == "": + opt.language = "english" + + mode, convertion_chain = chain(opt, initial_version) + opt.warning("convertion chain: " + str(convertion_chain), 3) + + for step in convertion_chain: + convert = getattr(__import__("lyx_" + step), mode) + convert(header,body, opt) + + set_version(header, version) + set_format(header, opt.format) + write_file(header, body, opt) if __name__ == "__main__": main(sys.argv) diff --git a/lib/lyx2lyx/lyx_0_12.py b/lib/lyx2lyx/lyx_0_12.py new file mode 100644 index 0000000000..9a44e1da37 --- /dev/null +++ b/lib/lyx2lyx/lyx_0_12.py @@ -0,0 +1,262 @@ +# This file is part of lyx2lyx +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2003-2004 José Matos +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import re +import string +from parser_tools import find_token, find_re, check_token + + +def space_before_layout(lines): + i = 2 # skip first layout + while 1: + i = find_token(lines, '\\layout', i) + if i == -1: + break + + if lines[i - 1] == '' and string.find(lines[i-2],'\\protected_separator') == -1: + del lines[i-1] + i = i + 1 + + +def formula_inset_space_eat(lines): + i=0 + while 1: + i = find_token(lines, "\\begin_inset Formula", i) + if i == -1: break + + if len(lines[i]) > 22 and lines[i][21] == ' ': + lines[i] = lines[i][:20] + lines[i][21:] + i = i + 1 + + +# Update from tabular format 2 to 4 +def update_tabular(lines): + lyxtable_re = re.compile(r".*\\LyXTable$") + i=0 + while 1: + i = find_re(lines, lyxtable_re, i) + if i == -1: + break + i = i + 1 + format = lines[i][8] + + lines[i]='multicol4' + i = i + 1 + rows = int(string.split(lines[i])[0]) + columns = int(string.split(lines[i])[1]) + + lines[i] = lines[i] + ' 0 0 -1 -1 -1 -1' + i = i + 1 + + for j in range(rows): + lines[i] = lines[i] + ' 0 0' + i = i + 1 + + for j in range(columns): + lines[i] = lines[i] + ' ' + i = i + 1 + + while lines[i]: + lines[i] = lines[i] + ' 0 0 0' + i = i + 1 + + +def final_dot(lines): + i = 0 + while i < len(lines): + if lines[i][-1:] == '.' and lines[i+1][:1] != '\\' and lines[i+1][:1] != ' ' and len(lines[i]) + len(lines[i+1])<= 72 and lines[i+1] != '': + lines[i] = lines[i] + lines[i+1] + del lines[i+1] + else: + i = i + 1 + + +def update_inset_label(lines): + i = 0 + while 1: + i = find_token(lines, '\\begin_inset Label', i) + if i == -1: + return + lines[i] = '\\begin_inset LatexCommand \label{' + lines[i][19:] + '}' + i = i + 1 + + +def update_latexdel(lines): + i = 0 + while 1: + i = find_token(lines, '\\begin_inset LatexDel', i) + if i == -1: + return + lines[i] = string.replace(lines[i],'\\begin_inset LatexDel', '\\begin_inset LatexCommand') + i = i + 1 + + +def update_vfill(lines): + for i in range(len(lines)): + lines[i] = string.replace(lines[i],'\\fill_top','\\added_space_top vfill') + lines[i] = string.replace(lines[i],'\\fill_bottom','\\added_space_bottom vfill') + + +def update_space_units(lines): + added_space_bottom = re.compile(r'\\added_space_bottom ([^ ]*)') + added_space_top = re.compile(r'\\added_space_top ([^ ]*)') + for i in range(len(lines)): + result = added_space_bottom.search(lines[i]) + if result: + old = '\\added_space_bottom ' + result.group(1) + new = '\\added_space_bottom ' + str(float(result.group(1))) + 'cm' + lines[i] = string.replace(lines[i], old, new) + + result = added_space_top.search(lines[i]) + if result: + old = '\\added_space_top ' + result.group(1) + new = '\\added_space_top ' + str(float(result.group(1))) + 'cm' + lines[i] = string.replace(lines[i], old, new) + + +def update_inset_accent(lines): + pass + + +def remove_cursor(lines): + i = 0 + cursor_re = re.compile(r'.*(\\cursor \d*)') + while 1: + i = find_re(lines, cursor_re, i) + if i == -1: + break + cursor = cursor_re.search(lines[i]).group(1) + lines[i]= string.replace(lines[i], cursor, '') + i = i + 1 + + +def remove_empty_insets(lines): + i = 0 + while 1: + i = find_token(lines, '\\begin_inset ',i) + if i == -1: + break + if lines[i] == '\\begin_inset ' and lines[i+1] == '\\end_inset ': + del lines[i] + del lines[i] + i = i + 1 + + +def remove_formula_latex(lines): + i = 0 + while 1: + i = find_token(lines, '\\latex formula_latex ', i) + if i == -1: + break + del lines[i] + + i = find_token(lines, '\\latex default', i) + if i == -1: + break + del lines[i] + + +def add_end_document(lines): + i = find_token(lines, '\\the_end', 0) + if i == -1: + lines.append('\\the_end') + + +def header_update(lines, opt): + i = 0 + l = len(lines) + while i < l: + if check_token(lines[i], '\\begin_preamble'): + i = find_token(lines, '\\end_preamble', i) + if i == -1: + opt.error('Unfinished preamble') + i = i + 1 + continue + + if lines[i][-1:] == ' ': + lines[i] = lines[i][:-1] + + if check_token(lines[i], '\\epsfig'): + lines[i] = string.replace(lines[i], '\\epsfig', '\\graphics') + i = i + 1 + continue + + if check_token(lines[i], '\\papersize'): + size = string.split(lines[i])[1] + new_size = size + paperpackage = "" + + if size == 'usletter': + new_size = 'letterpaper' + if size == 'a4wide': + new_size = 'Default' + paperpackage = "widemarginsa4" + + lines[i] = '\\papersize ' + new_size + i = i + 1 + if paperpackage: + lines.insert(i, '\\paperpackage ' + paperpackage) + i = i + 1 + + lines.insert(i,'\\use_geometry 0') + lines.insert(i + 1,'\\use_amsmath 0') + i = i + 2 + continue + + + if check_token(lines[i], '\\baselinestretch'): + size = string.split(lines[i])[1] + if size == '1.00': + name = 'single' + elif size == '1.50': + name = 'onehalf' + elif size == '2.00': + name = 'double' + else: + name = 'other ' + size + lines[i] = '\\spacing %s ' % name + i = i + 1 + continue + + i = i + 1 + + +def convert(header,body, opt): + header_update(header, opt) + add_end_document(body) + remove_cursor(body) + final_dot(body) + update_inset_label(body) + update_latexdel(body) + update_space_units(body) + update_inset_accent(body) + space_before_layout(body) + formula_inset_space_eat(body) + update_tabular(body) + update_vfill(body) + remove_empty_insets(body) + remove_formula_latex(body) + opt.format = 215 + + +def revert(header, body, opt): + opt.error("The convertion to an older format (%s) is not implemented." % opt.format) + + +if __name__ == "__main__": + pass diff --git a/lib/lyx2lyx/lyx_1_0_0.py b/lib/lyx2lyx/lyx_1_0_0.py new file mode 100644 index 0000000000..af35201b76 --- /dev/null +++ b/lib/lyx2lyx/lyx_1_0_0.py @@ -0,0 +1,29 @@ +# This file is part of lyx2lyx +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2004 José Matos +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +def convert(header, body, opt): + opt.format = 215 + + +def revert(header, body, opt): + opt.error("The convertion to an older format (%s) is not implemented." % opt.format) + + +if __name__ == "__main__": + pass + diff --git a/lib/lyx2lyx/lyx_1_0_1.py b/lib/lyx2lyx/lyx_1_0_1.py new file mode 100644 index 0000000000..af35201b76 --- /dev/null +++ b/lib/lyx2lyx/lyx_1_0_1.py @@ -0,0 +1,29 @@ +# This file is part of lyx2lyx +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2004 José Matos +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +def convert(header, body, opt): + opt.format = 215 + + +def revert(header, body, opt): + opt.error("The convertion to an older format (%s) is not implemented." % opt.format) + + +if __name__ == "__main__": + pass + diff --git a/lib/lyx2lyx/lyx_1_1_4.py b/lib/lyx2lyx/lyx_1_1_4.py new file mode 100644 index 0000000000..af35201b76 --- /dev/null +++ b/lib/lyx2lyx/lyx_1_1_4.py @@ -0,0 +1,29 @@ +# This file is part of lyx2lyx +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2004 José Matos +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +def convert(header, body, opt): + opt.format = 215 + + +def revert(header, body, opt): + opt.error("The convertion to an older format (%s) is not implemented." % opt.format) + + +if __name__ == "__main__": + pass + diff --git a/lib/lyx2lyx/lyx_1_1_5.py b/lib/lyx2lyx/lyx_1_1_5.py new file mode 100644 index 0000000000..d147b96bc3 --- /dev/null +++ b/lib/lyx2lyx/lyx_1_1_5.py @@ -0,0 +1,166 @@ +# This file is part of lyx2lyx +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2002-2004 José Matos +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import re +import string +from parser_tools import find_token, find_token_backwards, find_re + + +layout_exp = re.compile(r"\\layout (\S*)") +math_env = ["\\[","\\begin{eqnarray*}","\\begin{eqnarray}","\\begin{equation}"] + +def replace_protected_separator(lines): + i=0 + while 1: + i = find_token(lines, "\\protected_separator", i) + if i == -1: + break + j = find_token_backwards(lines, "\\layout", i) + #if j == -1: print error + layout = layout_exp.match(lines[j]).group(1) + + if layout == "LyX-Code": + result = "" + while lines[i] == "\\protected_separator ": + result = result + " " + del lines[i] + + lines[i-1] = lines[i-1] + result + lines[i] + else: + lines[i-1] = lines[i-1]+ "\\SpecialChar ~" + + del lines[i] + + +def merge_formula_inset(lines): + i=0 + while 1: + i = find_token(lines, "\\begin_inset Formula", i) + if i == -1: break + if lines[i+1] in math_env: + lines[i] = lines[i] + lines[i+1] + del lines[i+1] + i = i + 1 + + +# Update from tabular format 4 to 5 if necessary +def update_tabular(lines): + lyxtable_re = re.compile(r".*\\LyXTable$") + i=0 + while 1: + i = find_re(lines, lyxtable_re, i) + if i == -1: + break + i = i + 1 + format = lines[i][8] + if format != '4': + continue + + lines[i]='multicol5' + i = i + 1 + rows = int(string.split(lines[i])[0]) + columns = int(string.split(lines[i])[1]) + + i = i + rows + 1 + for j in range(columns): + col_info = string.split(lines[i]) + if len(col_info) == 3: + lines[i] = lines[i] + '"" ""' + else: + lines[i] = string.join(col_info[:3]) + ' "%s" ""' % col_info[3] + i = i + 1 + + while lines[i]: + lines[i] = lines[i] + ' "" ""' + i = i + 1 + + +def update_toc(lines): + i = 0 + while 1: + i = find_token(lines, '\\begin_inset LatexCommand \\tableofcontents', i) + if i == -1: + break + lines[i] = lines[i] + '{}' + i = i + 1 + + +def remove_cursor(lines): + i = find_token(lines, '\\cursor', 0) + if i != -1: + del lines[i] + + +def remove_vcid(lines): + i = find_token(lines, '\\lyxvcid', 0) + if i != -1: + del lines[i] + i = find_token(lines, '\\lyxrcsid', 0) + if i != -1: + del lines[i] + + +def first_layout(lines): + while (lines[0] == ""): + del lines[0] + if lines[0][:7] != "\\layout": + lines[:0] = ["\\layout Standard"] + + +def remove_space_in_units(lines): + margins = ["\\topmargin","\\rightmargin", + "\\leftmargin","\\bottommargin"] + + unit_rexp = re.compile(r'[^ ]* (.*) (.*)') + + begin_preamble = find_token(lines,"\\begin_preamble", 0) + end_preamble = find_token(lines, "\\end_preamble", 0) + for margin in margins: + i = 0 + while 1: + i = find_token(lines, margin, i) + if i == -1: + break + + if i > begin_preamble and i < end_preamble: + i = i + 1 + continue + + result = unit_rexp.search(lines[i]) + if result: + lines[i] = margin + " " + result.group(1) + result.group(2) + i = i + 1 + + +def convert(header, body, opt): + first_layout(body) + remove_vcid(header) + remove_cursor(body) + update_toc(body) + replace_protected_separator(body) + merge_formula_inset(body) + update_tabular(body) + remove_space_in_units(header) + opt.format = 216 + + +def revert(header, body, opt): + opt.error("The convertion to an older format (%s) is not implemented." % opt.format) + +if __name__ == "__main__": + pass diff --git a/lib/lyx2lyx/lyx_1_1_6.py b/lib/lyx2lyx/lyx_1_1_6.py new file mode 100644 index 0000000000..ce043abcc6 --- /dev/null +++ b/lib/lyx2lyx/lyx_1_1_6.py @@ -0,0 +1,288 @@ +# This file is part of lyx2lyx +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2002-2004 José Matos +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import re +import string +from parser_tools import find_re, find_tokens, find_token, check_token + + +lyxtable_re = re.compile(r".*\\LyXTable$") +def update_tabular(lines, opt): + i=0 + while 1: + i = find_re(lines, lyxtable_re, i) + if i == -1: + break + prop_dict = {"family" : "default", "series" : "default", + "shape" : "default", "size" : "default", + "emph" : "default", "bar" : "default", + "noun" : "default", "latex" : "default", "color" : "default"} + + # remove \LyXTable + lines[i] = lines[i][:-9] + i = i + 1 + lines.insert(i,'') + i = i + 1 + lines[i] = "\\begin_inset Tabular" + i = i + 1 + head = string.split(lines[i]) + rows = int(head[0]) + columns = int(head[1]) + + tabular_line = i + i = i +1 + lines.insert(i, '' % (head[2],head[3],head[4],head[5],head[6],head[7])) + + i = i +1 + + row_info = [] + cont_row = [] + for j in range(rows): + row_info.append(string.split(lines[i])) + if string.split(lines[i])[2] == '1': + cont_row.append(j) + del lines[i] + + column_info = [] + col_info_re = re.compile(r'(\d) (\d) (\d) (".*") (".*")') + for j in range(columns): + column_info.append(col_info_re.match(lines[i]).groups()) + del lines[i] + + cell_info = [] + cell_col = [] + ncells = 0 + cell_re = re.compile(r'(\d) (\d) (\d) (\d) (\d) (\d) (\d) (".*") (".*")') + for j in range(rows): + for k in range(columns): + #add column location to read properties + cell_info.append(cell_re.match(lines[i]).groups()) + cell_col.append(k) + if lines[i][0] != "2": + ncells = ncells + 1 + del lines[i] + + lines[tabular_line] = '' % (rows-len(cont_row),columns) + del lines[i] + if not lines[i]: + del lines[i] + + # Read cells + l = 0 + cell_content = [] + for j in range(rows): + cell_content.append([]) + + for j in range(rows): + for k in range(columns): + cell_content[j].append([]) + + for j in range(rows): + for k in range(columns): + m = j*columns + k + if cell_info[m][0] == '2': + continue + + if l == ncells -1: + # the end variable refers to cell end, not to file end. + end = find_tokens(lines, ['\\layout','\\the_end','\\end_deeper','\\end_float'], i) + else: + end = find_token(lines, '\\newline', i) + + if end == -1: + opt.error("Malformed LyX file.") + + end = end - i + while end > 0: + cell_content[j][k].append(lines[i]) + del lines[i] + end = end -1 + + if string.find(lines[i],'\\newline') != -1: + del lines[i] + l = l + 1 + + tmp = [] + tmp.append("") + + for j in range(rows): + if j in cont_row: + continue + tmp.append('' % (row_info[j][0],row_info[j][1],row_info[j][3])) + + for k in range(columns): + if j: + tmp.append('') + else: + tmp.append('' % (column_info[k][0],column_info[k][1], column_info[k][2], column_info[k][3], column_info[k][4])) + m = j*columns + k + + leftline = int(column_info[k][1]) + if cell_info[m][0] == '1': + n = m + 1 + while n < rows * columns - 1 and cell_info[n][0] == '2': + n = n + 1 + rightline = int(column_info[cell_col[n-1]][2]) + else: + # not a multicolumn main cell + rightline = int(column_info[k][2]) + + tmp.append('' % (cell_info[m][0],cell_info[m][1],cell_info[m][2],cell_info[m][3],leftline,rightline,cell_info[m][5],cell_info[m][6],cell_info[m][7],cell_info[m][8])) + tmp.append('\\begin_inset Text') + tmp.append('') + tmp.append('\\layout Standard') + tmp.append('') + + if cell_info[m][0] != '2': + paragraph = [] + if cell_info[m][4] == '1': + l = j + paragraph = paragraph + cell_content[j][k] + while cell_info[m][4] == '1': + m = m + columns + l = l + 1 + if l >= rows: break + paragraph = paragraph + cell_content[l][k] + else: + paragraph = cell_content[j][k] + tmp = tmp + set_paragraph_properties(paragraph, prop_dict) + + tmp.append('\\end_inset ') + tmp.append('') + tmp.append('') + tmp.append('') + + tmp.append('') + tmp.append('') + tmp.append('\\end_inset ') + tmp.append('') + tmp.append('') + lines[i:i] = tmp + + i = i + len(tmp) + + +prop_exp = re.compile(r"\\(\S*)\s*(\S*)") + +def set_paragraph_properties(lines, prop_dict): + # we need to preserve the order of options + properties = ["family","series","shape","size", + "emph","bar","noun","latex","color"] + prop_value = {"family" : "default", "series" : "medium", + "shape" : "up", "size" : "normal", + "emph" : "off", "bar" : "no", + "noun" : "off", "latex" : "no_latex", "color" : "none"} + + start = 0 + end = 0 + i = 0 + n = len(lines) + + #skip empty lines + while i +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import re +import string +from parser_tools import find_token + +def bool_table(item): + if item == "0": + return "false" + # should emit a warning if item != "1" + return "true" + + +align_table = {"0": "top", "2": "left", "4": "right", "8": "center"} +use_table = {"0": "none", "1": "parbox"} +table_meta_re = re.compile(r'') + +def update_tabular(lines, opt): + i=0 + while 1: + i = find_token(lines, '\\begin_inset Tabular', i) + if i == -1: + break + + i = i +1 + + # scan table header meta-info + res = table_meta_re.match( lines[i] ) + if res: + val = res.groups() + lines[i] = '' % val + + j = find_token(lines, '', i) + 1 + if j == 0: + opt.warning( "Error: Bad lyx format i=%d j=%d" % (i,j)) + break + + new_table = table_update(lines[i:j]) + lines[i:j] = new_table + i = i + len(new_table) + + +col_re = re.compile(r'') +cell_re = re.compile(r'') +features_re = re.compile(r'') +row_re = re.compile(r'') + +def table_update(lines): + lines[1] = string.replace(lines[1], '' or lines[i] == '': + del lines[i] + continue + + res = cell_re.match(lines[i]) + if res: + val = res.groups() + lines[i] = '' % ( val[0], align_table[val[1]], align_table[val[2]], bool_table(val[3]), bool_table(val[4]), bool_table(val[5]), bool_table(val[6]), bool_table(val[7]), use_table[val[8]], val[9], val[10]) + + res = row_re.match(lines[i]) + if res: + val = res.groups() + lines[i] = '' % (bool_table(val[0]), bool_table(val[1]), bool_table(val[2])) + + i = i + 1 + + j = len(col_info) + for i in range(j): + res = col_re.match(col_info[i]) + if res: + val = res.groups() + col_info[i] = '' \ + % ( align_table[val[0]], align_table[val[1]], bool_table(val[2]), bool_table(val[3]), val[4],val[5]) + + return lines[:2] + col_info + lines[2:] + + +def convert(header, body, opt): + update_tabular(body, opt) + opt.format = 218 + + +def revert(header, body, opt): + opt.error("The convertion to an older format (%s) is not implemented." % opt.format) + + +if __name__ == "__main__": + pass diff --git a/lib/lyx2lyx/lyx_1_2.py b/lib/lyx2lyx/lyx_1_2.py new file mode 100644 index 0000000000..6849c25735 --- /dev/null +++ b/lib/lyx2lyx/lyx_1_2.py @@ -0,0 +1,563 @@ +# This file is part of lyx2lyx +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2002 Dekel Tsur +# Copyright (C) 2004 José Matos +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import string +import re + +from parser_tools import find_token, find_token_backwards, get_next_paragraph,\ + find_tokens, find_end_of_inset, find_re, \ + is_nonempty_line, get_paragraph, find_nonempty_line, \ + get_value, get_tabular_lines, check_token + +floats = { + "footnote": ["\\begin_inset Foot", + "collapsed true"], + "margin": ["\\begin_inset Marginal", + "collapsed true"], + "fig": ["\\begin_inset Float figure", + "wide false", + "collapsed false"], + "tab": ["\\begin_inset Float table", + "wide false", + "collapsed false"], + "alg": ["\\begin_inset Float algorithm", + "wide false", + "collapsed false"], + "wide-fig": ["\\begin_inset Float figure", + "wide true", + "collapsed false"], + "wide-tab": ["\\begin_inset Float table", + "wide true", + "collapsed false"] +} + +font_tokens = ["\\family", "\\series", "\\shape", "\\size", "\\emph", + "\\bar", "\\noun", "\\color", "\\lang", "\\latex"] + +pextra_type3_rexp = re.compile(r".*\\pextra_type\s+3") +pextra_rexp = re.compile(r"\\pextra_type\s+(\S+)"+\ + r"(\s+\\pextra_alignment\s+(\S+))?"+\ + r"(\s+\\pextra_hfill\s+(\S+))?"+\ + r"(\s+\\pextra_start_minipage\s+(\S+))?"+\ + r"(\s+(\\pextra_widthp?)\s+(\S*))?") + + +def get_width(mo): + if mo.group(10): + if mo.group(9) == "\\pextra_widthp": + return mo.group(10)+"col%" + else: + return mo.group(10) + else: + return "100col%" + + +# +# Change \begin_float .. \end_float into \begin_inset Float .. \end_inset +# +def remove_oldfloat(lines, opt): + i = 0 + while 1: + i = find_token(lines, "\\begin_float", i) + if i == -1: + break + # There are no nested floats, so finding the end of the float is simple + j = find_token(lines, "\\end_float", i+1) + + floattype = string.split(lines[i])[1] + if not floats.has_key(floattype): + opt.warning("Error! Unknown float type " + floattype) + floattype = "fig" + + # skip \end_deeper tokens + i2 = i+1 + while check_token(lines[i2], "\\end_deeper"): + i2 = i2+1 + if i2 > i+1: + j2 = get_next_paragraph(lines, j+1) + lines[j2:j2] = ["\\end_deeper "]*(i2-(i+1)) + + new = floats[floattype]+[""] + + # Check if the float is floatingfigure + k = find_re(lines, pextra_type3_rexp, i, j) + if k != -1: + mo = pextra_rexp.search(lines[k]) + width = get_width(mo) + lines[k] = re.sub(pextra_rexp, "", lines[k]) + new = ["\\begin_inset Wrap figure", + 'width "%s"' % width, + "collapsed false", + ""] + + new = new+lines[i2:j]+["\\end_inset ", ""] + + # After a float, all font attributes are reseted. + # We need to output '\foo default' for every attribute foo + # whose value is not default before the float. + # The check here is not accurate, but it doesn't matter + # as extra '\foo default' commands are ignored. + # In fact, it might be safer to output '\foo default' for all + # font attributes. + k = get_paragraph(lines, i) + flag = 0 + for token in font_tokens: + if find_token(lines, token, k, i) != -1: + if not flag: + # This is not necessary, but we want the output to be + # as similar as posible to the lyx format + flag = 1 + new.append("") + if token == "\\lang": + new.append(token+" "+ opt.language) + else: + new.append(token+" default ") + + lines[i:j+1] = new + i = i+1 + + +pextra_type2_rexp = re.compile(r".*\\pextra_type\s+[12]") +pextra_type2_rexp2 = re.compile(r".*(\\layout|\\pextra_type\s+2)") + +def remove_pextra(lines): + i = 0 + flag = 0 + while 1: + i = find_re(lines, pextra_type2_rexp, i) + if i == -1: + break + + mo = pextra_rexp.search(lines[i]) + width = get_width(mo) + + if mo.group(1) == "1": + # handle \pextra_type 1 (indented paragraph) + lines[i] = re.sub(pextra_rexp, "\\leftindent "+width+" ", lines[i]) + i = i+1 + continue + + # handle \pextra_type 2 (minipage) + position = mo.group(3) + hfill = mo.group(5) + lines[i] = re.sub(pextra_rexp, "", lines[i]) + + start = ["\\begin_inset Minipage", + "position " + position, + "inner_position 0", + 'height "0pt"', + 'width "%s"' % width, + "collapsed false" + ] + if flag: + flag = 0 + if hfill: + start = ["","\hfill",""]+start + else: + start = ["\\layout Standard"] + start + + j0 = find_token_backwards(lines,"\\layout", i-1) + j = get_next_paragraph(lines, i) + + count = 0 + while 1: + # collect more paragraphs to the minipage + count = count+1 + if j == -1 or not check_token(lines[j], "\\layout"): + break + i = find_re(lines, pextra_type2_rexp2, j+1) + if i == -1: + break + mo = pextra_rexp.search(lines[i]) + if not mo: + break + if mo.group(7) == "1": + flag = 1 + break + lines[i] = re.sub(pextra_rexp, "", lines[i]) + j = find_tokens(lines, ["\\layout", "\\end_float"], i+1) + + mid = lines[j0:j] + end = ["\\end_inset "] + + lines[j0:j] = start+mid+end + i = i+1 + + +def is_empty(lines): + return filter(is_nonempty_line, lines) == [] + + +move_rexp = re.compile(r"\\(family|series|shape|size|emph|numeric|bar|noun|end_deeper)") +ert_rexp = re.compile(r"\\begin_inset|\\hfill|.*\\SpecialChar") +spchar_rexp = re.compile(r"(.*)(\\SpecialChar.*)") +ert_begin = ["\\begin_inset ERT", + "status Collapsed", + "", + "\\layout Standard"] + + +def remove_oldert(lines): + i = 0 + while 1: + i = find_tokens(lines, ["\\latex latex", "\\layout LaTeX"], i) + if i == -1: + break + j = i+1 + while 1: + # \end_inset is for ert inside a tabular cell. The other tokens + # are obvious. + j = find_tokens(lines, ["\\latex default", "\\layout", "\\begin_inset", "\\end_inset", "\\end_float", "\\the_end"], + j) + if check_token(lines[j], "\\begin_inset"): + j = find_end_of_inset(lines, j)+1 + else: + break + + if check_token(lines[j], "\\layout"): + while j-1 >= 0 and check_token(lines[j-1], "\\begin_deeper"): + j = j-1 + + # We need to remove insets, special chars & font commands from ERT text + new = [] + new2 = [] + if check_token(lines[i], "\\layout LaTeX"): + new = ["\layout Standard", "", ""] + # We have a problem with classes in which Standard is not the default layout! + + k = i+1 + while 1: + k2 = find_re(lines, ert_rexp, k, j) + inset = hfill = specialchar = 0 + if k2 == -1: + k2 = j + elif check_token(lines[k2], "\\begin_inset"): + inset = 1 + elif check_token(lines[k2], "\\hfill"): + hfill = 1 + del lines[k2] + j = j-1 + else: + specialchar = 1 + mo = spchar_rexp.match(lines[k2]) + lines[k2] = mo.group(1) + specialchar_str = mo.group(2) + k2 = k2+1 + + tmp = [] + for line in lines[k:k2]: + # Move some lines outside the ERT inset: + if move_rexp.match(line): + if new2 == []: + # This is not necessary, but we want the output to be + # as similar as posible to the lyx format + new2 = [""] + new2.append(line) + elif not check_token(line, "\\latex"): + tmp.append(line) + + if is_empty(tmp): + if filter(lambda x:x != "", tmp) != []: + if new == []: + # This is not necessary, but we want the output to be + # as similar as posible to the lyx format + lines[i-1] = lines[i-1]+" " + else: + new = new+[" "] + else: + new = new+ert_begin+tmp+["\\end_inset ", ""] + + if inset: + k3 = find_end_of_inset(lines, k2) + new = new+[""]+lines[k2:k3+1]+[""] # Put an empty line after \end_inset + k = k3+1 + # Skip the empty line after \end_inset + if not is_nonempty_line(lines[k]): + k = k+1 + new.append("") + elif hfill: + new = new+["\hfill", ""] + k = k2 + elif specialchar: + if new == []: + # This is not necessary, but we want the output to be + # as similar as posible to the lyx format + lines[i-1] = lines[i-1]+specialchar_str + new = [""] + else: + new = new+[specialchar_str, ""] + k = k2 + else: + break + + new = new+new2 + if not check_token(lines[j], "\\latex "): + new = new+[""]+[lines[j]] + lines[i:j+1] = new + i = i+1 + + # Delete remaining "\latex xxx" tokens + i = 0 + while 1: + i = find_token(lines, "\\latex ", i) + if i == -1: + break + del lines[i] + + +# ERT insert are hidden feature of lyx 1.1.6. This might be removed in the future. +def remove_oldertinset(lines): + i = 0 + while 1: + i = find_token(lines, "\\begin_inset ERT", i) + if i == -1: + break + j = find_end_of_inset(lines, i) + k = find_token(lines, "\\layout", i+1) + l = get_paragraph(lines, i) + if lines[k] == lines[l]: # same layout + k = k+1 + new = lines[k:j] + lines[i:j+1] = new + i = i+1 + + +def is_ert_paragraph(lines, i): + if not check_token(lines[i], "\\layout Standard"): + return 0 + + i = find_nonempty_line(lines, i+1) + if not check_token(lines[i], "\\begin_inset ERT"): + return 0 + + j = find_end_of_inset(lines, i) + k = find_nonempty_line(lines, j+1) + return check_token(lines[k], "\\layout") + + +def combine_ert(lines): + i = 0 + while 1: + i = find_token(lines, "\\begin_inset ERT", i) + if i == -1: + break + j = get_paragraph(lines, i) + count = 0 + text = [] + while is_ert_paragraph(lines, j): + + count = count+1 + i2 = find_token(lines, "\\layout", j+1) + k = find_token(lines, "\\end_inset", i2+1) + text = text+lines[i2:k] + j = find_token(lines, "\\layout", k+1) + if j == -1: + break + + if count >= 2: + j = find_token(lines, "\\layout", i+1) + lines[j:k] = text + + i = i+1 + + +oldunits = ["pt", "cm", "in", "text%", "col%"] + +def get_length(lines, name, start, end): + i = find_token(lines, name, start, end) + if i == -1: + return "" + x = string.split(lines[i]) + return x[2]+oldunits[int(x[1])] + + +def write_attribute(x, token, value): + if value != "": + x.append("\t"+token+" "+value) + + +def remove_figinset(lines): + i = 0 + while 1: + i = find_token(lines, "\\begin_inset Figure", i) + if i == -1: + break + j = find_end_of_inset(lines, i) + + if ( len(string.split(lines[i])) > 2 ): + lyxwidth = string.split(lines[i])[3]+"pt" + lyxheight = string.split(lines[i])[4]+"pt" + else: + lyxwidth = "" + lyxheight = "" + + filename = get_value(lines, "file", i+1, j) + + width = get_length(lines, "width", i+1, j) + # what does width=5 mean ? + height = get_length(lines, "height", i+1, j) + rotateAngle = get_value(lines, "angle", i+1, j) + if width == "" and height == "": + size_type = "0" + else: + size_type = "1" + + flags = get_value(lines, "flags", i+1, j) + x = int(flags)%4 + if x == 1: + display = "monochrome" + elif x == 2: + display = "gray" + else: + display = "color" + + subcaptionText = "" + subcaptionLine = find_token(lines, "subcaption", i+1, j) + if subcaptionLine != -1: + subcaptionText = lines[subcaptionLine][11:] + if subcaptionText != "": + subcaptionText = '"'+subcaptionText+'"' + + k = find_token(lines, "subfigure", i+1,j) + if k == -1: + subcaption = 0 + else: + subcaption = 1 + + new = ["\\begin_inset Graphics FormatVersion 1"] + write_attribute(new, "filename", filename) + write_attribute(new, "display", display) + if subcaption: + new.append("\tsubcaption") + write_attribute(new, "subcaptionText", subcaptionText) + write_attribute(new, "size_type", size_type) + write_attribute(new, "width", width) + write_attribute(new, "height", height) + if rotateAngle != "": + new.append("\trotate") + write_attribute(new, "rotateAngle", rotateAngle) + write_attribute(new, "rotateOrigin", "leftBaseline") + write_attribute(new, "lyxsize_type", "1") + write_attribute(new, "lyxwidth", lyxwidth) + write_attribute(new, "lyxheight", lyxheight) + new = new + ["\end_inset"] + lines[i:j+1] = new + + +attr_re = re.compile(r' \w*="(false|0|)"') +line_re = re.compile(r'<(features|column|row|cell)') + +def update_tabular(lines): + i = 0 + while 1: + i = find_token(lines, '\\begin_inset Tabular', i) + if i == -1: + break + + for k in get_tabular_lines(lines, i): + if check_token(lines[k], "