From 12d77c2a8fa6ea324cab624e48cf582fd955959d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Matox?= Date: Sat, 8 Nov 2008 18:40:54 +0000 Subject: [PATCH] Update lyx2lyx to 1.6.0 level git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/branches/BRANCH_1_5_X@27348 a592a061-630c-0410-9148-cb99ea01b6c8 --- lib/lyx2lyx/ChangeLog | 665 -------- lib/lyx2lyx/LyX.py | 231 ++- lib/lyx2lyx/Makefile.am | 1 + lib/lyx2lyx/lyx2lyx | 126 +- lib/lyx2lyx/lyx_1_4.py | 2 +- lib/lyx2lyx/lyx_1_5.py | 40 +- lib/lyx2lyx/lyx_1_6.py | 3229 +++++++++++++++++++++++++++++++++++ lib/lyx2lyx/parser_tools.py | 21 + lib/lyx2lyx/profiling.py | 7 +- status.15x | 8 +- 10 files changed, 3494 insertions(+), 836 deletions(-) delete mode 100644 lib/lyx2lyx/ChangeLog create mode 100644 lib/lyx2lyx/lyx_1_6.py diff --git a/lib/lyx2lyx/ChangeLog b/lib/lyx2lyx/ChangeLog deleted file mode 100644 index cf6919c097..0000000000 --- a/lib/lyx2lyx/ChangeLog +++ /dev/null @@ -1,665 +0,0 @@ -2006-03-14 Georg Baum - - * lyx_1_5.py: new file, handle new format 246 - * LyX.py: handle new format 246 - * lyx_1_4.py (revert_booktabs): move to lyx_1_5.py - -2006-03-06 José Matos - - * lyx_1_4.py (remove_paperpackage): Only reset the papersize for - a4* paperpackages. - -2006-02-22 Georg Baum - - * lyx_1_4.py (convert_amsmath, revert_amsmath): new, convert ams math - settings. - -2006-02-05 Georg Baum - - * LyX.py: new member is_default_layout() - * LyX.py: new member default_layout - * parser_tools.py (get_layout): new, extract layout name from line - * lyx_1_1_5.py, lyx_1_1_6.py, lyx_1_2.py, lyx_1_4.py: Replace all - occurences of the "Standard" layout with file.default_layout (bug 2026) - -2006-02-02 Georg Baum - - * lyx_1_4.py (remove_branches): new, remove branch insets - -2005-12-01 José Matos - - * LyX.py (choose_io): replace open and make the choice more transparent. - -2005-11-24 José Matos - - * lyx_1_0_0.py (obsolete_latex_title): "LaTeX Title" -> "Title" - * (update_tabular): update from tabular format 3 to 4 if necessary. - -2005-11-20 Georg Baum - - * lyx_1_4.py (convert_frameless_box): fix file format argument of - insert_ert - -2005-10-12 Jürgen Spitzmüller - - * LyX.py: enlarge range to current format (245); - do not use \quotes_times anymore on NewFile. - * lyx_1_4.py (remove_quotestimes): remove param \quotes_times (bug 2090). - -2005-09-28 José Matos - - * LyX.py: fix relation_format reversion - -2005-09-28 Jürgen Spitzmüller - - * LyX.py: enlarge range to current format (244). - * lyx_1_4.py (revert_spaces): fix so that new space insets are reverted - to ERT. - * lyx_1_4.py (rename_spaces, revert_space_names): some InsetSpace types - had to be renamed; conversion takes place between 243<->244. - -2005-09-19 Georg Baum - - * parser_tools.py (get_paragraph, get_next_paragraph): add format - argument and make them work with formats newer than 220 - * lyx_1_2.py (remove_oldfloat, remove_pextra, remove_oldertinset, - combine_ert): adjust to the changes above - * lyx_1_4.py (convert_breaks, revert_breaks): better conversion of - lyxlines - * lyx_1_4.py (convert_ertbackslash, convert_ertlen, insert_ert): - add format argument and make it work with formats newer than 240 - * lyx_1_4.py (convert_frameless_box): adjust to the changes above - * lyx_1_4.py (ert2latex): new, convert ERT code to LaTeX - * lyx_1_4.py (lyxsize2latexsize): new, convert LyX font size to LaTeX - -2005-09-18 Georg Baum - - * LyX.py (LyX_Base): fix paragraph parameter check - * LyX.py (NewFile): remove paperpackage from header - -2005-09-09 José Matos - - * lyx_1_1_6fix3.py (update_tabular): fix vertical alignment convertion. - -2005-08-28 Georg Baum - - * lyx_1_4.py (convert_vspace): rename to revert_breaks and revert - \lyxline and \newpage, too - -2005-08-30 Georg Baum - - * lyx_1_4.py (add_to_preamble): fix invocation of find_token (bug 2004) - -2005-08-18 José Matos - - * lyx_1_4.py (remove_paperpackage): fix bug 2001. - -2005-08-18 José Matos - - * LyX.py (read, write): add preamble as data member of LyX_Base, - remove if from the header. - - * lyx_0_12.py (header_update): - * lyx_1_1_5.py (remove_space_in_units): - * lyx_1_4.py (add_to_preamble, convert_frameless_box): use the new scheme. - - * lyx_1_2.py (change_header): change name to reflect its content. - -2005-07-29 José Matos - - * lyx_1_4.py: - * LyX.py: add \leftindent to the list of allowed paragraph parameters. - -2005-07-29 José Matos - - * lyx_1_4.py (remove_paperpackage): Take into account the lines - added to preamble. - -2005-07-29 José Matos - - * lyx_1_4.py: Fix a4 package removal when the preamble is already there. - -2005-07-29 José Matos - - * lyx_1_4.py: Fix widemarginsa4 convertion. - -2005-07-29 José Matos - - * lyx_1_4.py: \end_header was added in 222, not 223 - -2005-07-29 José Matos - - * lyx_1_4.py: - * LyX.py: do not ignore format 222. - -2005-07-22 José Matos - - * lyx_1_4.py (convert_paperpackage, revert_paperpackage): - remove wrong comments - - * LyX.py : add 1.3.6 to the releases list - -2005-07-18 José Matos - - * lyx_1_4.py (convert_minipage, convert_frameless_box): small - fixes to minipages convertions and retroversions. - -2005-07-18 José Matos - - * lyx_1_4.py (convert_french): fix two typos (Thanks to Georg Baum). - -2005-07-18 José Matos - - * lyx_1_4.py (convert_french): convert language also in the body. - -2005-07-15 José Matos - - * Makefile.am: new file for correct dealing with python scripts. - * .cvsignore: ignore Makefile(.in) files. - -2005-07-12 José Matos - - * lyx_1_4.py (add_to_preamble): Make it more robust. - (convert_frameless_box): Fix wrong type for parameter. - (revert_paperpackage): Consider empty paper package case. - -2005-07-08 José Matos - - * lyx_0_12.py (update_tabular): Support old tables format 1. - -2005-07-08 José Matos - - * lyx_1_1_5.py (latexdel_getargs, update_ref, update_latexdel): - Remove latexdel insets comming from sgml2lyx (ref, url and htmlurl). - -2005-06-21 Georg Baum - - * lyx_1_4.py (convert_french): change language frenchb to french - for format 242. - -2005-07-07 José Matos - - * LyX.py (read): Ignore whitelines on header. Fix reading the - first body line. - -2005-07-06 José Matos - - * lyx_1_1_5.py (replace_protected_separator): Make it robust - to layout name absence. - -2005-07-06 José Matos - - * LyX.py (read): Add support for cases where the body begins - without a whiteline before. - -2005-07-06 José Matos - - * lyx_1_4.py (paperpackage): Fix empty paperpackage case. - -2005-07-06 José Matos - - * LyX.py (warning): Prefix warnings with label "Warning: ". - * lyx_1_4.py (add_end_layout): Handle truncated files. - -2005-07-06 José Matos - - * lyx_1_4.py (convert_paperpackage): older tex2lyx generated files - had \paperpackage with 'default' instead of 'none'. - -2005-07-05 José Matos - - * LyX.py (LyX_Base): - * LyX.py (error): - * LyX.py (convert): - * lyx2lyx: Implement return codes consistently: - 0 - OK. - 1 - Irrecoverable error. - 2 - Recovered from error(s). - -2005-07-05 José Matos - - * LyX.py (LyX_Base): - * LyX.py (File): - * lyx2lyx (usage): - * lyx2lyx (parse_options): - * lyx2lyx (main): Add support for ignoring any errors during the - file convertion. - -2005-07-05 José Matos - - * lyx_0_12.py (obsolete_latex_title): Obsolote old style. - -2005-05-18 Angus Leeming - - * lyx2lyx (parse_options): Add the description of the '-f' option - back again. - -2005-05-18 Georg Baum - - * lyx_1_4.py (convert_breaks): Don't treat every token that starts - with '\\' as paragraph parameter - -2005-05-06 José Matos - - * lyx_1_4.py (convert_breaks): put all paragraph parameters into a - single line. - -2005-05-04 José Matos - - * LyX.py: fix allowed parameters for paragraphs. - -2005-04-26 Georg Baum - - * lyx_1_4.py (convert_breaks): fix spelling - * lyx_1_4.py (convert_breaks): fix copy-and-paste error - -2005-02-20 Georg Baum - - * lyx_1_4.py (lyx_support_escape): new - * lyx_1_4.py (revert_eqref): new, convert - '\begin_inset LatexCommand \eqref{label}' to ERT - * lyx_1_4.py (revert): call revert_eqref in step 223 -> 221 - -2005-02-17 Georg Baum - - * lyx_1_4.py (convert_table_valignment_middle, - revert_valignment_middle): use regex to recognize - '\\begin_inset Tabular' and '\\begin_inset Tabular' - * lyx_1_2.py (update_tabular, update_longtables): ditto - * lyx_1_1_6fix3.py (update_tabular): ditto - -2005-02-15 José Matos - - * lyx_1_2.py (remove_pextra): fix bug 1816. - -2005-02-06 Georg Baum - - * lyx_1_4.py (convert_ertbackslash): convert '\n', too - * lyx_1_4.py (convert_len): new, split from convert_ertlen - * lyx_1_4.py (insert_ert): new - * lyx_1_4.py (add_to_preamble): new - * lyx_1_4.py (convert_frameless_box): better conversion of parboxes - and minipages with unsupported parameters - -2005-02-03 Georg Baum - - * LyX.py: format up to 241 - * lyx_1_4.py (convert_ert_paragraphs, revert_ert_paragraphs): new - * lyx_1_4.py, LyX.py: handle new format 241 - -2005-01-24 Georg Baum - - * LyX.py: format up to 240. - * lyx_1_4.py (convert_output_changes, revert_output_changes): new - -2005-01-06 José Matos - - * lyx_1_4.py (normalize_paragraph_params): add start_of_appendix - to the allowed parameters list. - -2005-01-06 José Matos - - * lyx_1_4.py (normalize_paragraph_params): update file format to 239. - - * LyX.py (convert): simplify code and add running times - information for higher debug levels. - -2005-01-04 José Matos - - * lyx_0_12.py: - * lyx_1_0_0.py: - * lyx_1_0_1.py: - * lyx_1_1_4.py: - * lyx_1_1_5.py: - * lyx_1_1_6.py: - * lyx_1_1_6fix3.py: - * lyx_1_2.py: - * lyx_1_3.py: - * lyx_1_4.py: convert and revert change from functions to lists. - - * LyX.py: - * lyx2lyx: version -> version_lyx2lyx - - * LyX.py (convert): put all the convertion logic here. - -2005-01-04 José Matos - - * LyX.py (set_format): fix typo. - - * lyx_0_12.py: - * lyx_1_0_0.py: - * lyx_1_0_1.py: - * lyx_1_1_4.py: - * lyx_1_1_5.py: - * lyx_1_1_6.py: - * lyx_1_1_6fix3.py: - * lyx_1_2.py: - * lyx_1_3.py: - * lyx_1_4.py: unify the call convention of convertion - functions. Now they all accept a file. - -2004-12-06 Georg Baum - - * lyx_1_4.py, LyX.py: handle new format 239 - * lyx_1_4.py (revert_booktabs): move to 239 -> 238 conversion - -2004-12-03 José Matos - - * LyX.py: format up to 238. - * lyx_1_4.py: - * lyx_0_12.py (update_latexaccents): consider the cases where the - inset is updated. - -2004-12-03 José Matos - - * lyx_1_2.py (update_longtable): Update longtables to table format 3. - -2004-12-02 José Matos - - * lyx_0_12.py (update_latexaccents): convert old style latexaccents. - -2004-11-29 José Matos - - * lyx_1_2.py (convert): rename opt to file, as in all other files. - -2004-12-06 Georg Baum - - * lyx_1_4.py, LyX.py: handle new format 238 - * lyx_1_4.py (revert_booktabs): new - -2004-10-28 José Matos - - * LyX.pm: add internal documentation. - -2004-10-17 José Matos - - * lyx2lyx: moved code to LyX module making effectively lyx2lyx and - interface to the LyX module. - - * LyX.py: white space changes. New class that serves as the basis - to two derived classes. One for reading and another for new files. - New function get_toc, to be used in Doc_toc.py in the - documentation directory. - New class paragraph, to read paragraphs from the lyx file. - -2004-10-10 José Matos - - * .cvsignore: add entries related with profiling lyx2lyx. - * lyx2lyx (main): place all program inside this function, to allow - it to be called from profiling. - * profiling.py: new file to profile lyx2lyx. - -2004-10-09 José Matos - - * LyX.py: add support for format 237, fix variables type, - new function formats_list(). - - * lyx2lyx: print list of available formats on request. - - * lyx_1_4.py: add support for 237, reorganize directory functions. - -2004-09-29 José Matos - - * lyx_1_4.py (get_end_format): simplify index. - -2004-09-12 Georg Baum - - * lyx_1_4.py (convert_ertbackslash): insert the new line after the - backslash, this did only work by accident in most cases - - * lyx_1_4.py: unify warning messages - -2004-08-19 José Matos - - * lyx_1_4.lyx (add_end_layout): fix \end_layout interaction with - \end_deeper. - -2004-08-16 José Matos - - * lyx_1_4.lyx (convert_comment, convert_breaks, convert_frameless_box): - (convert_names, add_begin_body, strip_end_space): use the same policy - of lyx of not using spaces as the last character in a line that starts - with a command token (\xxxxx). - -2004-08-15 José Matos - - * lyx_1_4.py (normalize_papersize, denormalize_papersize): - \papersize Default -> \papersize default - \papersize Custom -> \papersize custom - -2004-08-15 José Matos - - * LyX.py: new file that gathers all the knowleadge of the LyX file - format. This can be used as library. - - * parser_tools.py: moved all the functions that are not related - with the parser to LyX.py. - - * lyx2lyx: is just a client of the LyX.py library. - - * lyx_.py (convert, revert): renamed previous opt to file. Change - the arguments since now file contains both the header and the - body. - -2004-08-14 José Matos - - * lyx_1_4.py: - * parser_tools.py: up the format to 236. - -2004-08-05 José Matos - - * lyx_1.4.py (remove_color_default): move - \color default -> \color inherit - -2004-08-05 José Matos - - * parser_tools.py (read_file): remove \r from line's end when present. - -2004-07-01 Georg Baum - - * lyx_1_4.py (convert_paperpackage): new, convert paperpackage setting - * lyx_1_4.py (revert_paperpackage): new, revert paperpackage setting - * lyx_1_4.py (revert, convert): handle format 235 - * parser_tools.py: up the format to 235. - -2004-05-12 Angus Leeming - - * lyx_1_4.py (convert_cite_engine, revert_cite_engine): new functions - to convert the code that specifies the type of the citation engine - (basic, natbib or jurabib). - - * parser_tools.py: up the format to 234. - -2004-05-11 José Matos - - * parser_tools.py (get_backend): get the document backend. - * lyx2lyx (main): new member of the document structure, - the textclass and backend, that default to article and latex. - * lyx_1_4.py (add_end_layout): fix bug of mixed \begin_deeper - and \end_layout - (insert_tracking_changes): insert \tracking_changes 0, if not present - in the header. - (convert_names, revert_names): for docbook documents transform - the styles FirstName and Surname into character styles. - -2004-05-03 José Matos - - * lyx_1_4.py (convert_graphics): - * lyx2lyx: introduce new member of the structure class, dir which - carries the directory of the converted file. - * lyx2lyx: move default warning level to 1. - -2004-04-29 Georg Baum - - * lyx_1_4.py (convert_graphics): new, convert graphics filenames - * lyx_1_4.py (revert, convert): handle format 233 - * lyx2lyx: up the format to 233. - -2004-04-19 José Matos - - * parser_tools.py (chain): fix the detection of the last format for - revertions. - -2004-04-19 Martin Vermeer - - * lyx_1_4.py (convert_frameless_box): Replace instead of adding - new code. - -2004-04-14 José Matos - - * error.py - * lyxconvert_* - * lyxrevert_*: removed - - * lyx_0_12.py - * lyx_1_0_0.py - * lyx_1_0_1.py - + lyx_1_1_4.py - * lyx_1_1_5.py - * lyx_1_1_6.py - * lyx_1_1_6fix3.py - * lyx_1_2.py - * lyx_1_3.py - * lyx_1_4.py: Added file with the same content as the previous that - were removed. - - * lyx2lyx - * parser_tools.py: reworked for better modularity. - -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. - - * lyx2lyx: up the format to 231. - -2004-03-26 Georg Baum - - * lyxrevert_225.py (convert_frameless_box): fix minipage ERT output - -2004-02-25 Jürgen Spitzmüller - - * lyx2lyx: up the format to 230. - -2004-02-04 José Matos - * lyxconvert_210.py: add two new transforms: - remove_empty_insets and remove_formula_latex - little fix to existing transformations. - -2004-02-03 José Matos - - * lyxconvert216.py: one line fix for out of range error. - -2004-02-01 Georg Baum - - * lyxconvert2*.py: quiet encoding warning in python 2.3 - * lyxrevert_22[3-9].py: quiet encoding warning in python 2.3 - -2004-01-06 Georg Baum - - * lyxrevert_228.py: convert ERT status, too - * lyxconvert_227.py: ditto, also stop at \\begin_alyout and not - \\layout in convert_collapsable() - * lyxconvert_228.py (convert_minipage): Add status tag conversion - * lyxrevert_225.py: Convert vspace and frameless box insets - * lyxrevert_22[3-8].py: fix the 'é' in José's name - -2003-12-29 Jürgen Spitzmüller - - * lyx2lyx: up the format to 229. - * lyxconvert_224.py (convert_minipage): remove function... - * lyxconvert_228.py: ...and place it here. - * lyxrevert_229.py: new file (bare bones). - -2003-12-19 Angus Leeming - - * lyxconvert_227.py (convert_collapsable): - * lyxrevert_228.py (convert_collapsable): a more robust method of - finding the collapsed status. - -2003-12-18 Georg Baum - - * lyxrevert_228.py: fix box status conversion - * lyxconvert_227.py: ditto - -2003-12-16 José Matos - - * lyxrevert_228.py: fix sys import. - -2003-12-16 José Matos - - * lyxconvert_227.py: fix sys import. - -2003-12-15 Angus Leeming - - * lyx2lyx: - * lyxconvert_227.py: - * lyxrevert_228.py: convert the InsetCollapsable format between - formats 227 and 228. - -2003-12-10 Angus Leeming - - * lyxrevert_227.py: InsetExternal gains a 'draft' option, so remove - this when reverting to format 226. - -2003-12-10 Angus Leeming - - * lyx2lyx: up the format to 227. - (lyxformat): squash latent bug when reporting an inability to convert - to the desired format. - - * lyxconvert_226.py: - * lyxrevert_227.py: convert the Box inset between formats 226 and 227. - -2003-12-10 Angus Leeming - - * lyx2lyx: up the format to 226. - - * lyxconvert_225.py: - * lyxrevert_226.py: convert the Note inset between formats 225 and 226. - -2003-12-05 José Matos - - * error.py: - * parser_tools.py: quiet encoding warning in python 2.3. - - * lyx2lyx: add logfile as an option. - -2003-12-03 José Matos - - * lyx2lyx: update copyright date - * lyxconvert_224.py (convert_breaks): add vertical space convertion. - -2003-11-14 Kornel Benko - - * lyxconvert_224.py (convert_minipage): fix convertion of minipages - from lyx 1.3.x. - -2003-11-14 José Matos - - * lyxconvert_224.py (convert_breaks): avoid removal of paragraph - arguments when a page breake or a line were present. - -2003-11-07 José Matos - - * lyxconvert_224.py (convert_minipage): deal better with default - parameter of minipages from lyx 1.3.x - -2003-11-06 José Matos - - * lyxconvert_224.py (convert_breaks): Create an empty paragraph for - possible upper page and line breaks, if necessary. - -2003-10-27 José Matos - - * lyxconvert_223.py: - * lyxconvert_224.py (convert_minipage): move funtion to its right place. - (convert_breaks): convert line and page break, at bottom and top. diff --git a/lib/lyx2lyx/LyX.py b/lib/lyx2lyx/LyX.py index e0adfd25cb..db0b9afcda 100644 --- a/lib/lyx2lyx/LyX.py +++ b/lib/lyx2lyx/LyX.py @@ -17,7 +17,9 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from parser_tools import get_value, check_token, find_token,\ +" The LyX module has all the rules related with different lyx file formats." + +from parser_tools import get_value, check_token, find_token, \ find_tokens, find_end_of import os.path import gzip @@ -28,11 +30,11 @@ import time try: import lyx2lyx_version - version_lyx2lyx = lyx2lyx_version.version + version__ = lyx2lyx_version.version except: # we are running from build directory so assume the last version - version_lyx2lyx = '1.5.0svn' + version__ = '1.6.xsvn' -default_debug_level = 2 +default_debug__ = 2 #################################################################### # Private helper functions @@ -41,13 +43,13 @@ def find_end_of_inset(lines, i): " Find beginning of inset, where lines[i] is included." return find_end_of(lines, i, "\\begin_inset", "\\end_inset") -def generate_minor_versions(major, last_minor_version): +def minor_versions(major, last_minor_version): """ Generate minor versions, using major as prefix and minor versions from 0 until last_minor_version, plus the generic version. Example: - generate_minor_versions("1.2", 4) -> + minor_versions("1.2", 4) -> [ "1.2", "1.2.0", "1.2.1", "1.2.2", "1.2.3"] """ return [major] + [major + ".%d" % i for i in range(last_minor_version + 1)] @@ -65,20 +67,32 @@ original_version = re.compile(r".*?LyX ([\d.]*)") ## # file format information: # file, supported formats, stable release versions -format_relation = [("0_06", [200], generate_minor_versions("0.6" , 4)), - ("0_08", [210], generate_minor_versions("0.8" , 6) + ["0.7"]), - ("0_10", [210], generate_minor_versions("0.10", 7) + ["0.9"]), - ("0_12", [215], generate_minor_versions("0.12", 1) + ["0.11"]), - ("1_0", [215], generate_minor_versions("1.0" , 4)), - ("1_1", [215], generate_minor_versions("1.1" , 4)), +format_relation = [("0_06", [200], minor_versions("0.6" , 4)), + ("0_08", [210], minor_versions("0.8" , 6) + ["0.7"]), + ("0_10", [210], minor_versions("0.10", 7) + ["0.9"]), + ("0_12", [215], minor_versions("0.12", 1) + ["0.11"]), + ("1_0", [215], minor_versions("1.0" , 4)), + ("1_1", [215], minor_versions("1.1" , 4)), ("1_1_5", [216], ["1.1.5","1.1.5.1","1.1.5.2","1.1"]), ("1_1_6_0", [217], ["1.1.6","1.1.6.1","1.1.6.2","1.1"]), ("1_1_6_3", [218], ["1.1.6.3","1.1.6.4","1.1"]), - ("1_2", [220], generate_minor_versions("1.2" , 4)), - ("1_3", [221], generate_minor_versions("1.3" , 7)), - ("1_4", range(222,246), generate_minor_versions("1.4" , 5)), - ("1_5", range(246,277), generate_minor_versions("1.5" , 0))] + ("1_2", [220], minor_versions("1.2" , 4)), + ("1_3", [221], minor_versions("1.3" , 7)), + ("1_4", range(222,246), minor_versions("1.4" , 5)), + ("1_5", range(246,277), minor_versions("1.5" , 6)), + ("1_6", range(277,346), minor_versions("1.6" , 0))] +#################################################################### +# This is useful just for development versions # +# if the list of supported formats is empty get it from last step # +if not format_relation[-1][1]: + step, mode = format_relation[-1][0], "convert" + convert = getattr(__import__("lyx_" + step), mode) + format_relation[-1] = (step, + [conv[0] for conv in convert], + format_relation[-1][2]) +# # +#################################################################### def formats_list(): " Returns a list with supported file formats." @@ -99,7 +113,7 @@ def get_backend(textclass): " For _textclass_ returns its backend." if textclass == "linuxdoc" or textclass == "manpage": return "linuxdoc" - if textclass[:7] == "docbook": + if textclass.startswith("docbook") or textclass.startswith("agu-"): return "docbook" return "latex" @@ -113,6 +127,7 @@ def trim_eol(line): def get_encoding(language, inputencoding, format, cjk_encoding): + " Returns enconding of the lyx file" if format > 248: return "utf8" # CJK-LyX encodes files using the current locale encoding. @@ -121,7 +136,7 @@ def get_encoding(language, inputencoding, format, cjk_encoding): # argument. if cjk_encoding == 'auto': return locale.getpreferredencoding() - elif cjk_encoding != '': + elif cjk_encoding: return cjk_encoding from lyx2lyx_lang import lang if inputencoding == "auto" or inputencoding == "default": @@ -138,11 +153,11 @@ def get_encoding(language, inputencoding, format, cjk_encoding): ## # Class # -class LyX_Base: +class LyX_base: """This class carries all the information of the LyX file.""" - - def __init__(self, end_format = 0, input = "", output = "", error - = "", debug = default_debug_level, try_hard = 0, cjk_encoding = '', + + def __init__(self, end_format = 0, input = "", output = "", error = "", + debug = default_debug__, try_hard = 0, cjk_encoding = '', language = "english", encoding = "auto"): """Arguments: @@ -182,8 +197,9 @@ class LyX_Base: self.language = language - def warning(self, message, debug_level= default_debug_level): - " Emits warning to self.error, if the debug_level is less than the self.debug." + def warning(self, message, debug_level= default_debug__): + """ Emits warning to self.error, if the debug_level is less + than the self.debug.""" if debug_level <= self.debug: self.err.write("Warning: " + message + "\n") @@ -199,9 +215,10 @@ class LyX_Base: def read(self): - """Reads a file into the self.header and self.body parts, from self.input.""" + """Reads a file into the self.header and + self.body parts, from self.input.""" - while 1: + while True: line = self.input.readline() if not line: self.error("Invalid LyX file.") @@ -216,10 +233,14 @@ class LyX_Base: line = trim_eol(line) if check_token(line, '\\end_preamble'): break - - if line.split()[:0] in ("\\layout", "\\begin_layout", "\\begin_body"): - self.warning("Malformed LyX file: Missing '\\end_preamble'.") - self.warning("Adding it now and hoping for the best.") + + if line.split()[:0] in ("\\layout", + "\\begin_layout", "\\begin_body"): + + self.warning("Malformed LyX file:" + "Missing '\\end_preamble'." + "\nAdding it now and hoping" + "for the best.") self.preamble.append(line) @@ -230,7 +251,8 @@ class LyX_Base: if not line: continue - if line.split()[0] in ("\\layout", "\\begin_layout", "\\begin_body", "\\begin_deeper"): + if line.split()[0] in ("\\layout", "\\begin_layout", + "\\begin_body", "\\begin_deeper"): self.body.append(line) break @@ -245,9 +267,13 @@ class LyX_Base: self.textclass = get_value(self.header, "\\textclass", 0) self.backend = get_backend(self.textclass) self.format = self.read_format() - self.language = get_value(self.header, "\\language", 0, default = "english") - self.inputencoding = get_value(self.header, "\\inputencoding", 0, default = "auto") - self.encoding = get_encoding(self.language, self.inputencoding, self.format, self.cjk_encoding) + self.language = get_value(self.header, "\\language", 0, + default = "english") + self.inputencoding = get_value(self.header, "\\inputencoding", + 0, default = "auto") + self.encoding = get_encoding(self.language, + self.inputencoding, self.format, + self.cjk_encoding) self.initial_version = self.read_version() # Second pass over header and preamble, now we know the file encoding @@ -270,8 +296,8 @@ class LyX_Base: self.set_format() self.set_textclass() if self.encoding == "auto": - self.encoding = get_encoding(self.language, self.encoding, self.format, self.cjk_encoding) - + self.encoding = get_encoding(self.language, self.encoding, + self.format, self.cjk_encoding) if self.preamble: i = find_token(self.header, '\\textclass', 0) + 1 preamble = ['\\begin_preamble'] + self.preamble + ['\\end_preamble'] @@ -323,8 +349,9 @@ class LyX_Base: def read_version(self): - """ Searchs for clues of the LyX version used to write the file, returns the - most likely value, or None otherwise.""" + """ Searchs for clues of the LyX version used to write the + file, returns the most likely value, or None otherwise.""" + for line in self.header: if line[0] != "#": return None @@ -347,7 +374,8 @@ class LyX_Base: def set_version(self): " Set the header with the version used." - self.header[0] = "#LyX %s created this file. For more info see http://www.lyx.org/" % version_lyx2lyx + self.header[0] = " ".join(["#LyX %s created this file." % version__, + "For more info see http://www.lyx.org/"]) if self.header[1][0] == '#': del self.header[1] @@ -378,6 +406,56 @@ class LyX_Base: self.header[i] = "\\textclass %s" % self.textclass + #Note that the module will be added at the END of the extant ones + def add_module(self, module): + i = find_token(self.header, "\\begin_modules", 0) + if i == -1: + #No modules yet included + i = find_token(self.header, "\\textclass", 0) + if i == -1: + self.warning("Malformed LyX document: No \\textclass!!") + return + modinfo = ["\\begin_modules", module, "\\end_modules"] + self.header[i + 1: i + 1] = modinfo + return + j = find_token(self.header, "\\end_modules", i) + if j == -1: + self.warning("(add_module)Malformed LyX document: No \\end_modules.") + return + k = find_token(self.header, module, i) + if k != -1 and k < j: + return + self.header.insert(j, module) + + + def get_module_list(self): + i = find_token(self.header, "\\begin_modules", 0) + if (i == -1): + return [] + j = find_token(self.header, "\\end_modules", i) + return self.header[i + 1 : j] + + + def set_module_list(self, mlist): + modbegin = find_token(self.header, "\\begin_modules", 0) + newmodlist = ['\\begin_modules'] + mlist + ['\\end_modules'] + if (modbegin == -1): + #No modules yet included + tclass = find_token(self.header, "\\textclass", 0) + if tclass == -1: + self.warning("Malformed LyX document: No \\textclass!!") + return + modbegin = tclass + 1 + self.header[modbegin:modbegin] = newmodlist + return + modend = find_token(self.header, "\\end_modules", modbegin) + if modend == -1: + self.warning("(set_module_list)Malformed LyX document: No \\end_modules.") + return + newmodlist = ['\\begin_modules'] + mlist + ['\\end_modules'] + self.header[modbegin:modend + 1] = newmodlist + + def set_parameter(self, param, value): " Set the value of the header parameter." i = find_token(self.header, '\\' + param, 0) @@ -403,9 +481,11 @@ class LyX_Base: for step in convertion_chain: steps = getattr(__import__("lyx_" + step), mode) - self.warning("Convertion step: %s - %s" % (step, mode), default_debug_level + 1) + self.warning("Convertion step: %s - %s" % (step, mode), + default_debug__ + 1) if not steps: - self.error("The convertion to an older format (%s) is not implemented." % self.format) + self.error("The convertion to an older " + "format (%s) is not implemented." % self.format) multi_conv = len(steps) != 1 for version, table in steps: @@ -419,24 +499,26 @@ class LyX_Base: try: conv(self) except: - self.warning("An error ocurred in %s, %s" % (version, str(conv)), - default_debug_level) + self.warning("An error ocurred in %s, %s" % + (version, str(conv)), + default_debug__) if not self.try_hard: raise self.status = 2 else: - self.warning("%lf: Elapsed time on %s" % (time.time() - init_t, str(conv)), - default_debug_level + 1) - + self.warning("%lf: Elapsed time on %s" % + (time.time() - init_t, + str(conv)), default_debug__ + + 1) self.format = version if self.end_format == self.format: return def chain(self): - """ This is where all the decisions related with the convertion are taken. - It returns a list of modules needed to convert the LyX file from - self.format to self.end_format""" + """ This is where all the decisions related with the + convertion are taken. It returns a list of modules needed to + convert the LyX file from self.format to self.end_format""" self.start = self.format format = self.format @@ -451,7 +533,9 @@ class LyX_Base: if not correct_version: if format <= 215: - self.warning("Version does not match file format, discarding it. (Version %s, format %d)" %(self.initial_version, self.format)) + self.warning("Version does not match file format, " + "discarding it. (Version %s, format %d)" % + (self.initial_version, self.format)) for rel in format_relation: if format in rel[1]: initial_step = rel[0] @@ -493,15 +577,18 @@ class LyX_Base: if last_step[1][-1] == self.end_format: steps.pop() + self.warning("Convertion mode: %s\tsteps%s" %(mode, steps), 10) return mode, steps def get_toc(self, depth = 4): " Returns the TOC of this LyX document." - paragraphs_filter = {'Title' : 0,'Chapter' : 1, 'Section' : 2, 'Subsection' : 3, 'Subsubsection': 4} + paragraphs_filter = {'Title' : 0,'Chapter' : 1, 'Section' : 2, + 'Subsection' : 3, 'Subsubsection': 4} allowed_insets = ['Quotes'] - allowed_parameters = '\\paragraph_spacing', '\\noindent', '\\align', '\\labelwidthstring', "\\start_of_appendix", "\\leftindent" - + allowed_parameters = ('\\paragraph_spacing', '\\noindent', + '\\align', '\\labelwidthstring', + "\\start_of_appendix", "\\leftindent") sections = [] for section in paragraphs_filter.keys(): sections.append('\\begin_layout %s' % section) @@ -526,8 +613,9 @@ class LyX_Base: k = i + 1 # skip paragraph parameters - while not self.body[k].strip() or self.body[k].split()[0] in allowed_parameters: - k = k +1 + while not self.body[k].strip() or self.body[k].split()[0] \ + in allowed_parameters: + k += 1 while k < j: if check_token(self.body[k], '\\begin_inset'): @@ -541,7 +629,7 @@ class LyX_Base: k = end + 1 else: par.append(self.body[k]) - k = k + 1 + k += 1 # trim empty lines in the end. while par and par[-1].strip() == '': @@ -554,19 +642,23 @@ class LyX_Base: return toc_par -class File(LyX_Base): +class File(LyX_base): " This class reads existing LyX files." - def __init__(self, end_format = 0, input = "", output = "", error = "", debug = default_debug_level, try_hard = 0, cjk_encoding = ''): - LyX_Base.__init__(self, end_format, input, output, error, debug, try_hard, cjk_encoding) + + def __init__(self, end_format = 0, input = "", output = "", error = "", + debug = default_debug__, try_hard = 0, cjk_encoding = ''): + LyX_base.__init__(self, end_format, input, output, error, + debug, try_hard, cjk_encoding) self.read() -class NewFile(LyX_Base): +class NewFile(LyX_base): " This class is to create new LyX files." def set_header(self, **params): # set default values self.header.extend([ - "#LyX xxxx created this file. For more info see http://www.lyx.org/", + "#LyX xxxx created this file." + "For more info see http://www.lyx.org/", "\\lyxformat xxx", "\\begin_document", "\\begin_header", @@ -615,7 +707,8 @@ class NewFile(LyX_Base): class Paragraph: - # unfinished implementation, it is missing the Text and Insets representation. + # unfinished implementation, it is missing the Text and Insets + # representation. " This class represents the LyX paragraphs." def __init__(self, name, body=[], settings = [], child = []): """ Parameters: @@ -629,7 +722,9 @@ class Paragraph: self.child = child def asLines(self): - " Converts the paragraph to a list of strings, representing it in the LyX file." + """ Converts the paragraph to a list of strings, representing + it in the LyX file.""" + result = ['','\\begin_layout %s' % self.name] result.extend(self.settings) result.append('') @@ -645,13 +740,3 @@ class Paragraph: result.append('\\end_deeper') return result - - -class Inset: - " This class represents the LyX insets." - pass - - -class Text: - " This class represents simple chuncks of text." - pass diff --git a/lib/lyx2lyx/Makefile.am b/lib/lyx2lyx/Makefile.am index d047bc0d5e..b499a5d541 100644 --- a/lib/lyx2lyx/Makefile.am +++ b/lib/lyx2lyx/Makefile.am @@ -27,6 +27,7 @@ dist_lyx2lyx_PYTHON = \ lyx_1_3.py \ lyx_1_4.py \ lyx_1_5.py \ + lyx_1_6.py \ profiling.py \ test_parser_tools.py diff --git a/lib/lyx2lyx/lyx2lyx b/lib/lyx2lyx/lyx2lyx index 8c7b98b263..3a040a67d0 100755 --- a/lib/lyx2lyx/lyx2lyx +++ b/lib/lyx2lyx/lyx2lyx @@ -1,6 +1,7 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (C) 2002-2004 José Matos +# Copyright (C) 2002-2007 José Matos +# Copyright (C) 2002-2004 Dekel Tsur # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -16,86 +17,67 @@ # 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 +" Program used to convert between different versions of the lyx file format." +import optparse import sys import LyX -def usage(): - print """Usage: lyx2lyx [options] [file] -Convert old lyx file to newer format, files can be compressed with gzip. -If there no file is specified then the standard input is assumed, in this case -gziped files are not handled. -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) - default: level=1 - -e, --err error_file name of the error file or else goes to stderr - -f, --from version initial version (optional) - -t, --to version final version (optional) - -o, --output name name of the output file or else goes to stdout - -n, --try-hard try hard (ignore any convertion errors) - -c, --cjk [encoding] files in format 248 and lower are read and - written in the format of CJK-LyX. - If encoding is not given or 'auto' the encoding - is determined from the locale. - -q, --quiet same as --debug=0""" +def main(): + args = {} + args["usage"] = "usage: %prog [options] [file]" + args["version"] = """lyx2lyx, version %s +Copyright (C) 2007 José Matos and Dekel Tsur""" % LyX.version__ -def parse_options(argv): - _options = ["help", "version", "list", "debug=", "err=", "from=", "to=", "output=", "try-hard", "cjk", "quiet"] - try: - opts, args = getopt.getopt(argv[1:], "c:d:e:f:hlno:qt:v", _options) - except getopt.error: - usage() - sys.exit(2) + args["description"] = """Convert old lyx file to newer format, + files can be compressed with gzip. If there no file is specified then + the standard input is assumed, in this case gziped files are not + handled.""" - end_format, input, output, error, debug, try_hard = 0, "", "", "", LyX.default_debug_level, 0 - cjk_encoding = '' - for o, a in opts: - if o in ("-h", "--help"): - usage() - sys.exit() - if o in ("-v", "--version"): - print "lyx2lyx, version %s" %(LyX.version_lyx2lyx) - print "Copyright (C) 2002-2004 José Matos and Dekel Tsur" - sys.exit() - if o in ("-d", "--debug"): - debug = int(a) - if o in ("-q", "--quiet"): - debug = 0 - if o in ("-l", "--list"): - print LyX.formats_list() - sys.exit() - if o in ("-o", "--output"): - output = a - if o in ("-t", "--to"): - end_format = a - if o in ("-e","--err"): - error = a - if o in ("-n", "--try-hard"): - try_hard = 1 - if o in ("-c", "--cjk"): - if a == '': - cjk_encoding = 'auto' - else: - cjk_encoding = a + parser = optparse.OptionParser(**args) + + parser.set_defaults(debug=LyX.default_debug__, cjk_encoding = '') + parser.add_option("-d", "--debug", type="int", + help="level=0..2 (O_ quiet, 2_verbose) default: 1") + parser.add_option("-q", "--quiet", + action="store_const", const=0, dest="debug") + parser.add_option("-v", "--verbose", + action="store_const", const=1, dest="debug") + parser.add_option("--noisy", + action="store_const", const=2, dest="debug") + parser.add_option("-c", "--encoding", dest="cjk_encoding", + help="files in format 248 and lower are read and" + " written in the format of CJK-LyX." + "If encoding is not given or 'auto' the encoding" + "is determined from the locale.") + parser.add_option("-e", "--err", dest="error", + help= "file name of the error file else goes to stderr") + parser.add_option("-o", "--output", + help= "name of the output file else goes to stdout") + parser.add_option("-t", "--to", dest= "end_format", + help= "destination file format, default (latest)") + parser.add_option("-l", "--list", action="store_true", + help = "list all available formats") + parser.add_option("-n", "--try-hard", action="store_true", + help = "try hard (ignore any convertion errors)") + + (options, args) = parser.parse_args() if args: - input = args[0] + options.input = args[0] + else: + options.input = None - return end_format, input, output, error, debug, try_hard, cjk_encoding + if options.list: + print LyX.formats_list() + sys.exit() + else: + del options.list + doc = LyX.File(**options.__dict__) + doc.convert() + doc.write() -def main(argv): - end_format, input, output, error, debug, try_hard, cjk_encoding = parse_options(argv) - file = LyX.File(end_format, input, output, error, debug, try_hard, cjk_encoding) - - file.convert() - file.write() - - return file.status - + sys.exit(doc.status) if __name__ == "__main__": - sys.exit(main(sys.argv)) + main() diff --git a/lib/lyx2lyx/lyx_1_4.py b/lib/lyx2lyx/lyx_1_4.py index eb518eb588..0e04b478cf 100644 --- a/lib/lyx2lyx/lyx_1_4.py +++ b/lib/lyx2lyx/lyx_1_4.py @@ -2448,7 +2448,7 @@ def convert_sgml_paragraphs(document): i = i + 10 ## -# Convertion hub +# Conversion hub # supported_versions = ["1.4.%d" % i for i in range(3)] + ["1.4"] diff --git a/lib/lyx2lyx/lyx_1_5.py b/lib/lyx2lyx/lyx_1_5.py index 05fd93fdc2..62c314a14a 100644 --- a/lib/lyx2lyx/lyx_1_5.py +++ b/lib/lyx2lyx/lyx_1_5.py @@ -287,7 +287,7 @@ necessary parsing in modern formats than in ancient ones. inset_result = inset_re.match(document.body[i]) if inset_result: insets.append(inset_result.group(1)) - else: + else: insets.append("") elif find_token(document.body, "\\end_inset", i, i + 1) == i: del insets[-1] @@ -445,7 +445,7 @@ implemented.''' insets.append(line[13:].split()[0]) if line.find('\\end_inset') > -1: del insets[-1] - + # Try to write the line try: # If all goes well the line is written here @@ -676,7 +676,7 @@ def revert_commandparams(document): if i == -1: break name = document.body[i].split()[2] - j = find_end_of_inset(document.body, i + 1) + j = find_end_of_inset(document.body, i) preview_line = "" option1 = "" option2 = "" @@ -721,7 +721,7 @@ def revert_commandparams(document): lines.append('') lines.append('\\end_inset') document.body[i:j+1] = lines - i = j + 1 + i += len(lines) + 1 def revert_nomenclature(document): @@ -1287,7 +1287,7 @@ def normalize_font_whitespace_259(document): """ Before format 259 the font changes were ignored if a whitespace was the first or last character in the sequence, this function transfers the whitespace outside.""" - + char_properties = {"\\series": "default", "\\emph": "default", "\\color": "none", @@ -1298,8 +1298,8 @@ def normalize_font_whitespace_259(document): def normalize_font_whitespace_274(document): """ Before format 259 (sic) the font changes were ignored if a - whitespace was the first or last character in the sequence. This was - corrected for most font properties in format 259, but the language + whitespace was the first or last character in the sequence. This was + corrected for most font properties in format 259, but the language was forgotten then. This function applies the same conversion done there (namely, transfers the whitespace outside) for font language changes, as well.""" @@ -1310,11 +1310,11 @@ def normalize_font_whitespace_274(document): def get_paragraph_language(document, i): """ Return the language of the paragraph in which line i of the document body is. If the first thing in the paragraph is a \\lang command, that - is the paragraph's langauge; otherwise, the paragraph's language is the + is the paragraph's langauge; otherwise, the paragraph's language is the document's language.""" lines = document.body - + first_nonempty_line = \ find_nonempty_line(lines, find_beginning_of_layout(lines, i) + 1) @@ -1324,7 +1324,7 @@ def get_paragraph_language(document, i): return words[1] else: return document.language - + def normalize_font_whitespace(document, char_properties): """ Before format 259 the font changes were ignored if a whitespace was the first or last character in the sequence, this function @@ -1623,13 +1623,13 @@ def revert_tableborder(document): def revert_armenian(document): - - # set inputencoding from armscii8 to auto + + # set inputencoding from armscii8 to auto if document.inputencoding == "armscii8": i = find_token(document.header, "\\inputencoding", 0) if i != -1: document.header[i] = "\\inputencoding auto" - # check if preamble exists, if not k is set to -1 + # check if preamble exists, if not k is set to -1 i = 0 k = -1 while i < len(document.preamble): @@ -1646,7 +1646,7 @@ def revert_armenian(document): # create the preamble when it doesn't exist else: document.preamble.append('\\usepackage{armtex}') - # Set document language from armenian to english + # Set document language from armenian to english if document.language == "armenian": document.language = "english" i = find_token(document.header, "\\language", 0) @@ -1686,10 +1686,10 @@ def revert_preamble_listings_params(document): def revert_listings_inset(document): - r''' Revert listings inset to \lstinline or \begin, \end lstlisting, translate + r''' Revert listings inset to \lstinline or \begin, \end lstlisting, translate FROM -\begin_inset +\begin_inset lstparams "language=Delphi" inline true status open @@ -1787,7 +1787,7 @@ after label k = cap_end + 1 inlinecode = '' # looking for the oneline code for lstinline - inlinecode = document.body[find_end_of_layout(document.body, + inlinecode = document.body[find_end_of_layout(document.body, find_token(document.body, '\\begin_layout %s' % document.default_layout, i + 1) +1 ) - 1] if len(caption) > 0: if len(params) == 0: @@ -1806,7 +1806,7 @@ after label document.body[i:(j+1)] = [r'\begin_inset ERT', 'status %s' % status, r'\begin_layout %s' % document.default_layout, - '', + '', '', r'\backslash', 'lstinline%s{%s}' % (params, inlinecode), @@ -1834,7 +1834,7 @@ after label r'\end_layout', '', r'\end_inset'] - + def revert_include_listings(document): r''' Revert lstinputlisting Include option , translate @@ -1873,7 +1873,7 @@ lstinputlisting{file}[opt] # find command line lstinputlisting{file}[options] cmd, file, option = '', '', '' if re.match(r'\\(lstinputlisting){([.\w]*)}(.*)', document.body[i].split()[2]): - cmd, file, option = re.match(r'\\(lstinputlisting){([.\w]*)}(.*)', document.body[i].split()[2]).groups() + cmd, file, option = re.match(r'\\(lstinputlisting){([.\w]*)}(.*)', document.body[i].split()[2]).groups() option = option.replace('\\', '\\backslash\n') document.body[i : j + 1] = [r'\begin_inset ERT', 'status open', diff --git a/lib/lyx2lyx/lyx_1_6.py b/lib/lyx2lyx/lyx_1_6.py new file mode 100644 index 0000000000..cefeea3ee2 --- /dev/null +++ b/lib/lyx2lyx/lyx_1_6.py @@ -0,0 +1,3229 @@ +# This file is part of lyx2lyx +# -*- coding: utf-8 -*- +# Copyright (C) 2007-2008 The LyX Team +# +# 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. + +""" Convert files to the file format generated by lyx 1.6""" + +import re +import unicodedata +import sys, os + +from parser_tools import find_token, find_end_of, find_tokens, get_value, get_value_string + +#################################################################### +# Private helper functions + +def find_end_of_inset(lines, i): + " Find end of inset, where lines[i] is included." + return find_end_of(lines, i, "\\begin_inset", "\\end_inset") + +# WARNING! +# DO NOT do this: +# document.body[i] = wrap_insert_ert(...) +# wrap_into_ert may returns a multiline string, which should NOT appear +# in document.body. Insetad, do something like this: +# subst = wrap_inset_ert(...) +# subst = subst.split('\n') +# document.body[i:i+1] = subst +# i+= len(subst) - 1 +# where the last statement resets the counter to accord with the added +# lines. +def wrap_into_ert(string, src, dst): + '''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!""" + + if find_token(document.preamble, text[0], 0) != -1: + return + + 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", + "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth", + "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"} + + # Convert LyX units to LaTeX units + for unit in units.keys(): + if len.find(unit) != -1: + len = '%f' % (len2value(len) / 100) + len = len.strip('0') + units[unit] + break + + return len + +# Return the value of len without the unit in numerical form. +def len2value(len): + result = re.search('([+-]?[0-9.]+)', len) + if result: + return float(result.group(1)) + # No number means 1.0 + return 1.0 + +# Unfortunately, this doesn't really work, since Standard isn't always default. +# But it's as good as we can do right now. +def find_default_layout(document, start, end): + l = find_token(document.body, "\\begin_layout Standard", start, end) + if l == -1: + l = find_token(document.body, "\\begin_layout PlainLayout", start, end) + if l == -1: + l = find_token(document.body, "\\begin_layout Plain Layout", start, end) + return l + +def get_option(document, m, option, default): + l = document.body[m].find(option) + val = default + if l != -1: + val = document.body[m][l:].split('"')[1] + return val + +def remove_option(document, m, option): + l = document.body[m].find(option) + if l != -1: + val = document.body[m][l:].split('"')[1] + document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):] + return l + +def set_option(document, m, option, value): + l = document.body[m].find(option) + if l != -1: + oldval = document.body[m][l:].split('"')[1] + l = l + len(option + '="') + document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):] + else: + document.body[m] = document.body[m][:-1] + ' ' + 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 + + +unicode_reps = read_unicodesymbols() + +#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.''' + + if not data: + return [""] + retval = [] + + # Convert LaTeX to Unicode + # 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 unicode_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 + + 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 unicode_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): + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Tabular", i) + if i == -1: + return + j = find_end_of_inset(document.body, i + 1) + if j == -1: + document.warning("Malformed LyX document: Could not find end of tabular.") + continue + + nrows = int(document.body[i+1].split('"')[3]) + ncols = int(document.body[i+1].split('"')[5]) + + m = i + 1 + for k in range(nrows): + m = find_token(document.body, "", m + 1) + # first look for caption insets + mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend) + # then look for ERT captions + if mcap == -1: + mcap = find_token(document.body, "caption", m + 1, mend) + if mcap > -1: + mcap = find_token(document.body, "\\backslash", mcap - 1, mcap) + if mcap > -1: + caption = 'true' + if caption == 'true': + if (k == 0): + set_option(document, r, 'caption', 'true') + set_option(document, m, 'multicolumn', '1') + set_option(document, m, 'bottomline', 'false') + set_option(document, m, 'topline', 'false') + set_option(document, m, 'rightline', 'false') + set_option(document, m, 'leftline', 'false') + #j = find_end_of_inset(document.body, j + 1) + else: + set_option(document, m, 'multicolumn', '2') + m = m + 1 + m = m + 1 + + i = j + 1 + + +#FIXME Use of wrap_into_ert can confuse lyx2lyx +def revert_ltcaption(document): + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Tabular", i) + if i == -1: + return + j = find_end_of_inset(document.body, i + 1) + if j == -1: + document.warning("Malformed LyX document: Could not find end of tabular.") + continue + + m = i + 1 + nrows = int(document.body[i+1].split('"')[3]) + ncols = int(document.body[i+1].split('"')[5]) + + for k in range(nrows): + m = find_token(document.body, " 0 and mc_info[l*ncols + k - 1] == '0': + r = set_option(document, m, 'leftline', col_info[k][0]) + m = m + 1 + i = j + 1 + + +def revert_tablines(document): + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Tabular", i) + if i == -1: + return + j = find_end_of_inset(document.body, i + 1) + if j == -1: + document.warning("Malformed LyX document: Could not find end of tabular.") + continue + + m = i + 1 + nrows = int(document.body[i+1].split('"')[3]) + ncols = int(document.body[i+1].split('"')[5]) + + lines = [] + for k in range(nrows*ncols): + m = find_token(document.body, "= 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.' + i = 0 + r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?') + while True: + i = find_token(document.body, "\\begin_inset Include", i) + if i == -1: + return + line = document.body[i] + previewline = document.body[i + 1] + m = r.match(line) + if m == None: + document.warning("Unable to match line " + str(i) + " of body!") + i += 1 + continue + cmd = m.group(1) + fn = m.group(2) + opt = m.group(3) + insertion = ["\\begin_inset CommandInset include", + "LatexCommand " + cmd, previewline, + "filename \"" + fn + "\""] + newlines = 2 + if opt: + insertion.append("lstparams " + '"' + opt + '"') + newlines += 1 + document.body[i : i + 2] = insertion + i += newlines + + +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('lstparams "(.*)"') + while True: + i = find_token(document.body, "\\begin_inset CommandInset include", i) + if i == -1: + return + 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) + 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 = "" + if (cmd == "lstinputlisting"): + 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] + if previewline != "": + insertion.append(previewline) + document.body[i : nextline] = insertion + i += 2 + + +def revert_albanian(document): + "Set language Albanian to English" + i = 0 + if document.language == "albanian": + 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 albanian", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english") + j = j + 1 + + +def revert_lowersorbian(document): + "Set language lower Sorbian to English" + i = 0 + if document.language == "lowersorbian": + 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 lowersorbian", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english") + j = j + 1 + + +def revert_uppersorbian(document): + "Set language uppersorbian to usorbian as this was used in LyX 1.5" + i = 0 + if document.language == "uppersorbian": + document.language = "usorbian" + i = find_token(document.header, "\\language", 0) + if i != -1: + document.header[i] = "\\language usorbian" + j = 0 + while True: + j = find_token(document.body, "\\lang uppersorbian", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian") + j = j + 1 + + +def convert_usorbian(document): + "Set language usorbian to uppersorbian" + i = 0 + if document.language == "usorbian": + document.language = "uppersorbian" + i = find_token(document.header, "\\language", 0) + if i != -1: + document.header[i] = "\\language uppersorbian" + j = 0 + while True: + j = find_token(document.body, "\\lang usorbian", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian") + j = j + 1 + + +def convert_macro_global(document): + "Remove TeX code command \global when it is in front of a macro" + # math macros are nowadays already defined \global, so that an additional + # \global would make the document uncompilable, see + # http://bugzilla.lyx.org/show_bug.cgi?id=5371 + # We're looking for something like this: + # \begin_inset ERT + # status collapsed + # + # \begin_layout Plain Layout + # + # + # \backslash + # global + # \end_layout + # + # \end_inset + # + # + # \begin_inset FormulaMacro + # \renewcommand{\foo}{123} + # \end_inset + i = 0 + while True: + i = find_token(document.body, "\\begin_inset FormulaMacro", i) + if i == -1: + return + # if i <= 13, then there isn't enough room for the ERT + if i <= 12: + i += 1 + continue + if document.body[i-6] == "global": + del document.body[i-13 : i] + i = i - 12 + else: + i += 1 + + +def revert_macro_optional_params(document): + "Convert macro definitions with optional parameters into ERTs" + # Stub to convert macro definitions with one or more optional parameters + # into uninterpreted ERT insets + + +def revert_hyperlinktype(document): + 'Reverts hyperlink type' + i = 0 + j = 0 + while True: + i = find_token(document.body, "target", i) + if i == -1: + return + j = find_token(document.body, "type", i) + if j == -1: + return + if j == i + 1: + del document.body[j] + i = i + 1 + + +def revert_pagebreak(document): + 'Reverts pagebreak to ERT' + i = 0 + while True: + i = find_token(document.body, "\\pagebreak", i) + if i == -1: + return + document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Standard\n\n\n\\backslash\n' \ + 'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n' + i = i + 1 + + +def revert_linebreak(document): + 'Reverts linebreak to ERT' + i = 0 + while True: + i = find_token(document.body, "\\linebreak", i) + if i == -1: + return + document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Standard\n\n\n\\backslash\n' \ + 'linebreak{}\n\\end_layout\n\n\\end_inset\n\n' + i = i + 1 + + +def revert_latin(document): + "Set language Latin to English" + i = 0 + if document.language == "latin": + 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 latin", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang latin", "\\lang english") + j = j + 1 + + +def revert_samin(document): + "Set language North Sami to English" + i = 0 + if document.language == "samin": + 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 samin", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang samin", "\\lang english") + j = j + 1 + + +def convert_serbocroatian(document): + "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5" + i = 0 + if document.language == "serbocroatian": + document.language = "croatian" + i = find_token(document.header, "\\language", 0) + if i != -1: + document.header[i] = "\\language croatian" + j = 0 + while True: + j = find_token(document.body, "\\lang serbocroatian", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian") + j = j + 1 + + +def convert_framed_notes(document): + "Convert framed notes to boxes. " + i = 0 + while 1: + i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i) + if i == -1: + return + subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"), + 'position "t"', + 'hor_pos "c"', + 'has_inner_box 0', + 'inner_pos "t"', + 'use_parbox 0', + 'width "100col%"', + 'special "none"', + 'height "1in"', + 'height_special "totalheight"'] + document.body[i:i+1] = subst + i = i + 9 + + +def convert_module_names(document): + modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\ + 'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \ + 'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \ + 'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \ + 'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' } + modlist = document.get_module_list() + if len(modlist) == 0: + return + newmodlist = [] + for mod in modlist: + if modulemap.has_key(mod): + newmodlist.append(modulemap[mod]) + else: + document.warning("Can't find module %s in the module map!" % mod) + newmodlist.append(mod) + document.set_module_list(newmodlist) + + +def revert_module_names(document): + modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\ + 'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \ + 'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \ + 'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \ + 'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'} + modlist = document.get_module_list() + if len(modlist) == 0: + return + newmodlist = [] + for mod in modlist: + if modulemap.has_key(mod): + newmodlist.append(modulemap[mod]) + else: + document.warning("Can't find module %s in the module map!" % mod) + newmodlist.append(mod) + document.set_module_list(newmodlist) + + +def revert_colsep(document): + i = find_token(document.header, "\\columnsep", 0) + if i == -1: + return + colsepline = document.header[i] + r = re.compile(r'\\columnsep (.*)') + m = r.match(colsepline) + if not m: + document.warning("Malformed column separation line!") + return + colsep = m.group(1) + del document.header[i] + #it seems to be safe to add the package even if it is already used + pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"] + + add_to_preamble(document, pretext) + + +def revert_framed_notes(document): + "Revert framed boxes to notes. " + i = 0 + while 1: + i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i) + + if i == -1: + return + j = find_end_of_inset(document.body, i + 1) + if j == -1: + # should not happen + document.warning("Malformed LyX document: Could not find end of Box inset.") + k = find_token(document.body, "status", i + 1, j) + if k == -1: + document.warning("Malformed LyX document: Missing `status' tag in Box inset.") + return + status = document.body[k] + l = find_default_layout(document, i + 1, j) + if l == -1: + document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.") + return + m = find_token(document.body, "\\end_layout", i + 1, j) + if m == -1: + document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.") + return + ibox = find_token(document.body, "has_inner_box 1", i + 1, k) + pbox = find_token(document.body, "use_parbox 1", i + 1, k) + if ibox == -1 and pbox == -1: + document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note") + del document.body[i+1:k] + else: + document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless") + subst1 = [document.body[l], + "\\begin_inset Note Shaded", + status, + '\\begin_layout Standard'] + document.body[l:l + 1] = subst1 + subst2 = [document.body[m], "\\end_layout", "\\end_inset"] + document.body[m:m + 1] = subst2 + i = i + 1 + + +def revert_slash(document): + 'Revert \\SpecialChar \\slash{} to ERT' + r = re.compile(r'\\SpecialChar \\slash{}') + i = 0 + while i < len(document.body): + m = r.match(document.body[i]) + if m: + subst = ['\\begin_inset ERT', + 'status collapsed', '', + '\\begin_layout Standard', + '', '', '\\backslash', + 'slash{}', + '\\end_layout', '', + '\\end_inset', ''] + document.body[i: i+1] = subst + i = i + len(subst) + else: + i = i + 1 + + +def revert_nobreakdash(document): + 'Revert \\SpecialChar \\nobreakdash- to ERT' + i = 0 + while i < len(document.body): + line = document.body[i] + r = re.compile(r'\\SpecialChar \\nobreakdash-') + m = r.match(line) + if m: + subst = ['\\begin_inset ERT', + 'status collapsed', '', + '\\begin_layout Standard', '', '', + '\\backslash', + 'nobreakdash-', + '\\end_layout', '', + '\\end_inset', ''] + document.body[i:i+1] = subst + i = i + len(subst) + j = find_token(document.header, "\\use_amsmath", 0) + if j == -1: + document.warning("Malformed LyX document: Missing '\\use_amsmath'.") + return + document.header[j] = "\\use_amsmath 2" + else: + i = i + 1 + + +#Returns number of lines added/removed +def revert_nocite_key(body, start, end): + 'key "..." -> \nocite{...}' + r = re.compile(r'^key "(.*)"') + i = start + j = end + while i < j: + m = r.match(body[i]) + if m: + body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"] + j += 1 # because we added a line + i += 2 # skip that line + else: + del body[i] + j -= 1 # because we deleted a line + # no need to change i, since it now points to the next line + return j - end + + +def revert_nocite(document): + "Revert LatexCommand nocite to ERT" + i = 0 + while 1: + i = find_token(document.body, "\\begin_inset CommandInset citation", i) + if i == -1: + return + if (document.body[i+1] != "LatexCommand nocite"): + # note that we already incremented i + i = i + 1 + continue + insetEnd = find_end_of_inset(document.body, i) + if insetEnd == -1: + #this should not happen + document.warning("End of CommandInset citation not found in revert_nocite!") + return + + paramLocation = i + 2 #start of the inset's parameters + addedLines = 0 + document.body[i:i+2] = \ + ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"] + # that added two lines + paramLocation += 2 + insetEnd += 2 + #print insetEnd, document.body[i: insetEnd + 1] + insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd) + #print insetEnd, document.body[i: insetEnd + 1] + document.body.insert(insetEnd, "\\end_layout") + document.body.insert(insetEnd + 1, "") + i = insetEnd + 1 + + +def revert_btprintall(document): + "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}" + i = find_token(document.header, '\\use_bibtopic', 0) + if i == -1: + document.warning("Malformed lyx document: Missing '\\use_bibtopic'.") + return + if get_value(document.header, '\\use_bibtopic', 0) == "false": + i = 0 + while i < len(document.body): + i = find_token(document.body, "\\begin_inset CommandInset bibtex", i) + if i == -1: + return + j = find_end_of_inset(document.body, i + 1) + if j == -1: + #this should not happen + document.warning("End of CommandInset bibtex not found in revert_btprintall!") + j = len(document.body) + # this range isn't really right, but it should be OK, since we shouldn't + # see more than one matching line in each inset + addedlines = 0 + for k in range(i, j): + if (document.body[k] == 'btprint "btPrintAll"'): + del document.body[k] + subst = ["\\begin_inset ERT", + "status collapsed", "", + "\\begin_layout Standard", "", + "\\backslash", + "nocite{*}", + "\\end_layout", + "\\end_inset"] + document.body[i:i] = subst + addlines = addedlines + len(subst) - 1 + i = j + addedlines + + +def revert_bahasam(document): + "Set language Bahasa Malaysia to Bahasa Indonesia" + i = 0 + if document.language == "bahasam": + document.language = "bahasa" + i = find_token(document.header, "\\language", 0) + if i != -1: + document.header[i] = "\\language bahasa" + j = 0 + while True: + j = find_token(document.body, "\\lang bahasam", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa") + j = j + 1 + + +def revert_interlingua(document): + "Set language Interlingua to English" + i = 0 + if document.language == "interlingua": + 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 interlingua", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english") + j = j + 1 + + +def revert_serbianlatin(document): + "Set language Serbian-Latin to Croatian" + i = 0 + if document.language == "serbian-latin": + document.language = "croatian" + i = find_token(document.header, "\\language", 0) + if i != -1: + document.header[i] = "\\language croatian" + j = 0 + while True: + j = find_token(document.body, "\\lang serbian-latin", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian") + j = j + 1 + + +def revert_rotfloat(document): + " Revert sideways custom floats. " + i = 0 + while 1: + # whitespace intended (exclude \\begin_inset FloatList) + i = find_token(document.body, "\\begin_inset Float ", i) + if i == -1: + return + line = document.body[i] + r = re.compile(r'\\begin_inset Float (.*)$') + m = r.match(line) + if m == None: + document.warning("Unable to match line " + str(i) + " of body!") + i += 1 + continue + floattype = m.group(1) + if floattype == "figure" or floattype == "table": + i += 1 + continue + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.") + i += 1 + continue + addedLines = 0 + if get_value(document.body, 'sideways', i, j) == "false": + i += 1 + continue + l = find_default_layout(document, i + 1, j) + if l == -1: + document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.") + return + subst = ['\\begin_layout Standard', + '\\begin_inset ERT', + 'status collapsed', '', + '\\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) + subst = ['\\begin_inset ERT', 'status collapsed', '', + '\\begin_layout Standard', '', '', '\\backslash', + 'begin{sideways' + floattype + '}', + '\\end_layout', '', '\\end_inset', '', + '\\end_layout', ''] + document.body[i : i+1] = subst + addedLines += len(subst) - 1 + if floattype == "algorithm": + add_to_preamble(document, + ['% Commands inserted by lyx2lyx for sideways algorithm float', + '\\usepackage{rotfloat}', + '\\floatstyle{ruled}', + '\\newfloat{algorithm}{tbp}{loa}', + '\\floatname{algorithm}{Algorithm}']) + else: + document.warning("Cannot create preamble definition for custom float" + floattype + ".") + i += addedLines + 1 + + +def revert_widesideways(document): + " Revert wide sideways floats. " + i = 0 + while 1: + # whitespace intended (exclude \\begin_inset FloatList) + i = find_token(document.body, '\\begin_inset Float ', i) + if i == -1: + return + line = document.body[i] + r = re.compile(r'\\begin_inset Float (.*)$') + m = r.match(line) + if m == None: + document.warning("Unable to match line " + str(i) + " of body!") + i += 1 + continue + floattype = m.group(1) + if floattype != "figure" and floattype != "table": + i += 1 + continue + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.") + i += 1 + continue + if get_value(document.body, 'sideways', i, j) == "false" or \ + get_value(document.body, 'wide', i, j) == "false": + i += 1 + continue + l = find_default_layout(document, i + 1, j) + if l == -1: + document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.") + return + subst = ['\\begin_layout Standard', '\\begin_inset ERT', + 'status collapsed', '', + '\\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-1] + addedLines -= (l-1) - (i+1) + subst = ['\\begin_inset ERT', 'status collapsed', '', + '\\begin_layout Standard', '', '', '\\backslash', + 'begin{sideways' + floattype + '*}', '\\end_layout', '', + '\\end_inset', '', '\\end_layout', ''] + document.body[i : i+1] = subst + addedLines += len(subst) - 1 + add_to_preamble(document, ['\\usepackage{rotfloat}\n']) + i += addedLines + 1 + + +def revert_inset_embedding(document, type): + ' Remove embed tag from certain type of insets' + i = 0 + while 1: + i = find_token(document.body, "\\begin_inset %s" % type, i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.") + i = i + 1 + continue + k = find_token(document.body, "\tembed", i, j) + if k == -1: + k = find_token(document.body, "embed", i, j) + if k != -1: + del document.body[k] + i = i + 1 + + +def revert_external_embedding(document): + ' Remove embed tag from external inset ' + revert_inset_embedding(document, 'External') + + +def convert_subfig(document): + " Convert subfigures to subfloats. " + i = 0 + while 1: + addedLines = 0 + i = find_token(document.body, '\\begin_inset Graphics', i) + if i == -1: + return + endInset = find_end_of_inset(document.body, i) + if endInset == -1: + document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.") + i += 1 + continue + k = find_token(document.body, '\tsubcaption', i, endInset) + if k == -1: + i = endInset + continue + l = find_token(document.body, '\tsubcaptionText', i, endInset) + if l == -1: + caption = "" + else: + caption = document.body[l][16:].strip('"') + del document.body[l] + addedLines -= 1 + del document.body[k] + addedLines -= 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 + subst = ['', '\\end_inset', '', '\\end_layout'] + document.body[endInset : endInset] = subst + addedLines += len(subst) + i += addedLines + 1 + + +def revert_subfig(document): + " Revert subfloats. " + i = 0 + while 1: + # whitespace intended (exclude \\begin_inset FloatList) + i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i) + if i == -1: + return + j = 0 + addedLines = 0 + while j != -1: + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i]) + # document.warning(document.body[i-1] + "\n" + document.body[i+1]) + i += 1 + continue # this will get us back to the outer loop, since j == -1 + # look for embedded float (= subfloat) + # whitespace intended (exclude \\begin_inset FloatList) + k = find_token(document.body, '\\begin_inset Float ', i + 1, j) + if k == -1: + break + # is the subfloat aligned? + al = find_token(document.body, '\\align ', k - 1) + alignment_beg = "" + alignment_end = "" + if al != -1: + if get_value(document.body, '\\align', al) == "center": + alignment_beg = "\\backslash\nbegin{centering}" + alignment_end = "\\backslash\npar\\backslash\nend{centering}" + elif get_value(document.body, '\\align', al) == "left": + alignment_beg = "\\backslash\nbegin{raggedright}" + alignment_end = "\\backslash\npar\\backslash\nend{raggedright}" + elif get_value(document.body, '\\align', al) == "right": + alignment_beg = "\\backslash\nbegin{raggedleft}" + alignment_end = "\\backslash\npar\\backslash\nend{raggedleft}" + l = find_end_of_inset(document.body, k) + if l == -1: + document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).") + i += 1 + j == -1 + continue # escape to the outer loop + m = find_default_layout(document, k + 1, l) + # caption? + cap = find_token(document.body, '\\begin_inset Caption', k + 1, l) + caption = '' + shortcap = '' + capend = cap + if cap != -1: + capend = find_end_of_inset(document.body, cap) + if capend == -1: + document.warning("Malformed lyx document: Missing '\\end_inset' (caption).") + return + # label? + label = '' + lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend) + if lbl != -1: + lblend = find_end_of_inset(document.body, lbl + 1) + if lblend == -1: + document.warning("Malformed lyx document: Missing '\\end_inset' (label).") + return + for line in document.body[lbl:lblend + 1]: + if line.startswith('name '): + label = line.split()[1].strip('"') + break + else: + lbl = capend + lblend = capend + label = '' + # opt arg? + opt = find_token(document.body, '\\begin_inset OptArg', cap, capend) + if opt != -1: + optend = find_end_of_inset(document.body, opt) + if optend == -1: + document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).") + return + optc = find_default_layout(document, opt, optend) + if optc == -1: + document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.") + return + optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout") + for line in document.body[optc:optcend]: + if not line.startswith('\\'): + shortcap += line.strip() + else: + opt = capend + optend = capend + for line in document.body[cap:capend]: + if line in document.body[lbl:lblend]: + continue + elif line in document.body[opt:optend]: + continue + elif not line.startswith('\\'): + caption += line.strip() + if len(label) > 0: + caption += "\\backslash\nlabel{" + label + "}" + subst = '\\begin_layout Plain Layout\n\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Plain Layout\n\n}' + alignment_end + \ + '\n\\end_layout\n\n\\end_inset\n\n' \ + '\\end_layout\n\n\\begin_layout Plain Layout\n' + subst = subst.split('\n') + document.body[l : l+1] = subst + addedLines = len(subst) - 1 + # this is before l and so is unchanged by the multiline insertion + if cap != capend: + del document.body[cap:capend+1] + addedLines -= (capend + 1 - cap) + del document.body[k+1:m-1] + addedLines -= (m - 1 - (k + 1)) + insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Plain Layout\n\n' + alignment_beg + '\\backslash\n' \ + 'subfloat' + if len(shortcap) > 0: + insertion = insertion + "[" + shortcap + "]" + if len(caption) > 0: + insertion = insertion + "[" + caption + "]" + insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n' + insertion = insertion.split('\n') + document.body[k : k + 1] = insertion + addedLines += len(insertion) - 1 + if al != -1: + del document.body[al] + addedLines -= 1 + add_to_preamble(document, ['\\usepackage{subfig}\n']) + i += addedLines + 1 + + +def revert_wrapplacement(document): + " Revert placement options wrap floats (wrapfig). " + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Wrap figure", i) + if i == -1: + return + 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.") + 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): + " Remove \extra_embedded_files from buffer params " + i = find_token(document.header, '\\extra_embedded_files', 0) + if i == -1: + return + document.header.pop(i) + + +def convert_spaceinset(document): + " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' " + i = 0 + while i < len(document.body): + m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i]) + if m: + before = m.group(1) + after = m.group(2) + subst = [before, "\\begin_inset Space " + after, "\\end_inset"] + document.body[i: i+1] = subst + i = i + len(subst) + else: + i = i + 1 + + +def revert_spaceinset(document): + " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' " + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Space", i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Could not find end of space inset.") + continue + document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace') + del document.body[j] + + +def convert_hfill(document): + " Convert hfill to space inset " + i = 0 + while True: + i = find_token(document.body, "\\hfill", i) + if i == -1: + return + subst = document.body[i].replace('\\hfill', \ + '\n\\begin_inset Space \\hfill{}\n\\end_inset') + subst = subst.split('\n') + document.body[i : i+1] = subst + i += len(subst) + + +def revert_hfills(document): + ' Revert \\hfill commands ' + hfill = re.compile(r'\\hfill') + dotfill = re.compile(r'\\dotfill') + hrulefill = re.compile(r'\\hrulefill') + i = 0 + while True: + i = find_token(document.body, "\\InsetSpace", i) + if i == -1: + return + if hfill.search(document.body[i]): + document.body[i] = \ + document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill') + i += 1 + continue + if dotfill.search(document.body[i]): + subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \ + '\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Standard\n\n\n\\backslash\n' \ + 'dotfill{}\n\\end_layout\n\n\\end_inset\n\n') + subst = subst.split('\n') + document.body[i : i+1] = subst + i += len(subst) + continue + if hrulefill.search(document.body[i]): + subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \ + '\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Standard\n\n\n\\backslash\n' \ + 'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n') + subst = subst.split('\n') + document.body[i : i+1] = subst + i += len(subst) + continue + i += 1 + +def revert_hspace(document): + ' Revert \\InsetSpace \\hspace{} to ERT ' + i = 0 + hspace = re.compile(r'\\hspace{}') + hstar = re.compile(r'\\hspace\*{}') + while True: + i = find_token(document.body, "\\InsetSpace \\hspace", i) + if i == -1: + return + length = get_value(document.body, '\\length', i+1) + if length == '': + document.warning("Malformed lyx document: Missing '\\length' in Space inset.") + return + del document.body[i+1] + addedLines = -1 + if hstar.search(document.body[i]): + subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \ + '\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Standard\n\n\n\\backslash\n' \ + 'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n') + subst = subst.split('\n') + document.body[i : i+1] = subst + addedLines += len(subst) - 1 + i += addedLines + 1 + continue + if hspace.search(document.body[i]): + subst = document.body[i].replace('\\InsetSpace \\hspace{}', \ + '\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Standard\n\n\n\\backslash\n' \ + 'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n') + subst = subst.split('\n') + document.body[i : i+1] = subst + addedLines += len(subst) - 1 + i += addedLines + 1 + continue + i += 1 + + +def revert_protected_hfill(document): + ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT ' + i = 0 + while True: + i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Could not find end of space inset.") + continue + del document.body[j] + subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \ + '\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Standard\n\n\n\\backslash\n' \ + 'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n') + subst = subst.split('\n') + document.body[i : i+1] = subst + i += len(subst) + + +def revert_leftarrowfill(document): + ' Revert \\begin_inset Space \\leftarrowfill{} to ERT ' + i = 0 + while True: + i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Could not find end of space inset.") + continue + del document.body[j] + subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \ + '\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Standard\n\n\n\\backslash\n' \ + 'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n') + subst = subst.split('\n') + document.body[i : i+1] = subst + i += len(subst) + + +def revert_rightarrowfill(document): + ' Revert \\begin_inset Space \\rightarrowfill{} to ERT ' + i = 0 + while True: + i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Could not find end of space inset.") + continue + del document.body[j] + subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \ + '\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Standard\n\n\n\\backslash\n' \ + 'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n') + subst = subst.split('\n') + document.body[i : i+1] = subst + i += len(subst) + + +def revert_upbracefill(document): + ' Revert \\begin_inset Space \\upbracefill{} to ERT ' + i = 0 + while True: + i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Could not find end of space inset.") + continue + del document.body[j] + subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \ + '\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Standard\n\n\n\\backslash\n' \ + 'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n') + subst = subst.split('\n') + document.body[i : i+1] = subst + i += len(subst) + + +def revert_downbracefill(document): + ' Revert \\begin_inset Space \\downbracefill{} to ERT ' + i = 0 + while True: + i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Could not find end of space inset.") + continue + del document.body[j] + subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \ + '\\begin_inset ERT\nstatus collapsed\n\n' \ + '\\begin_layout Standard\n\n\n\\backslash\n' \ + 'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n') + subst = subst.split('\n') + document.body[i : i+1] = subst + i += len(subst) + + +def revert_local_layout(document): + ' Revert local layout headers.' + i = 0 + while True: + i = find_token(document.header, "\\begin_local_layout", i) + if i == -1: + return + j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout") + if j == -1: + # this should not happen + break + document.header[i : j + 1] = [] + + +def convert_pagebreaks(document): + ' Convert inline Newpage insets to new format ' + i = 0 + while True: + i = find_token(document.body, '\\newpage', i) + if i == -1: + break + document.body[i:i+1] = ['\\begin_inset Newpage newpage', + '\\end_inset'] + i = 0 + while True: + i = find_token(document.body, '\\pagebreak', i) + if i == -1: + break + document.body[i:i+1] = ['\\begin_inset Newpage pagebreak', + '\\end_inset'] + i = 0 + while True: + i = find_token(document.body, '\\clearpage', i) + if i == -1: + break + document.body[i:i+1] = ['\\begin_inset Newpage clearpage', + '\\end_inset'] + i = 0 + while True: + i = find_token(document.body, '\\cleardoublepage', i) + if i == -1: + break + document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage', + '\\end_inset'] + + +def revert_pagebreaks(document): + ' Revert \\begin_inset Newpage to previous inline format ' + i = 0 + while True: + i = find_token(document.body, '\\begin_inset Newpage', i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Could not find end of Newpage inset.") + continue + del document.body[j] + document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage') + document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak') + document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage') + document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage') + + +def convert_linebreaks(document): + ' Convert inline Newline insets to new format ' + i = 0 + while True: + i = find_token(document.body, '\\newline', i) + if i == -1: + break + document.body[i:i+1] = ['\\begin_inset Newline newline', + '\\end_inset'] + i = 0 + while True: + i = find_token(document.body, '\\linebreak', i) + if i == -1: + break + document.body[i:i+1] = ['\\begin_inset Newline linebreak', + '\\end_inset'] + + +def revert_linebreaks(document): + ' Revert \\begin_inset Newline to previous inline format ' + i = 0 + while True: + i = find_token(document.body, '\\begin_inset Newline', i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed LyX document: Could not find end of Newline inset.") + continue + del document.body[j] + document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline') + document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak') + + +def convert_japanese_plain(document): + ' Set language japanese-plain to japanese ' + i = 0 + if document.language == "japanese-plain": + 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-plain", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese") + j = j + 1 + + +def revert_pdfpages(document): + ' Revert pdfpages external inset to ERT ' + i = 0 + while 1: + i = find_token(document.body, "\\begin_inset External", i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.") + i = i + 1 + continue + if get_value(document.body, 'template', i, j) == "PDFPages": + filename = get_value(document.body, 'filename', i, j) + extra = '' + r = re.compile(r'\textra PDFLaTeX \"(.*)\"$') + for k in range(i, j): + m = r.match(document.body[k]) + if m: + extra = m.group(1) + angle = get_value(document.body, 'rotateAngle', i, j) + width = get_value(document.body, 'width', i, j) + height = get_value(document.body, 'height', i, j) + scale = get_value(document.body, 'scale', i, j) + keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j) + options = extra + if angle != '': + if options != '': + options += ",angle=" + angle + else: + options += "angle=" + angle + if width != '': + if options != '': + options += ",width=" + convert_len(width) + else: + options += "width=" + convert_len(width) + if height != '': + if options != '': + options += ",height=" + convert_len(height) + else: + options += "height=" + convert_len(height) + if scale != '': + if options != '': + options += ",scale=" + scale + else: + options += "scale=" + scale + if keepAspectRatio != '': + if options != '': + options += ",keepaspectratio" + else: + options += "keepaspectratio" + if options != '': + options = '[' + options + ']' + del document.body[i+1:j+1] + document.body[i:i+1] = ['\\begin_inset ERT', + 'status collapsed', + '', + '\\begin_layout Standard', + '', + '\\backslash', + 'includepdf' + options + '{' + filename + '}', + '\\end_layout', + '', + '\\end_inset'] + add_to_preamble(document, ['\\usepackage{pdfpages}\n']) + i = i + 1 + continue + i = i + 1 + + +def revert_mexican(document): + ' Set language Spanish(Mexico) to Spanish ' + i = 0 + if document.language == "spanish-mexico": + document.language = "spanish" + i = find_token(document.header, "\\language", 0) + if i != -1: + document.header[i] = "\\language spanish" + j = 0 + while True: + j = find_token(document.body, "\\lang spanish-mexico", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish") + j = j + 1 + + +def remove_embedding(document): + ' Remove embed tag from all insets ' + revert_inset_embedding(document, 'Graphics') + revert_inset_embedding(document, 'External') + revert_inset_embedding(document, 'CommandInset include') + revert_inset_embedding(document, 'CommandInset bibtex') + + +def revert_master(document): + ' Remove master param ' + i = find_token(document.header, "\\master", 0) + if i != -1: + del document.header[i] + + +def revert_graphics_group(document): + ' Revert group information from graphics insets ' + i = 0 + while 1: + i = find_token(document.body, "\\begin_inset Graphics", i) + if i == -1: + return + j = find_end_of_inset(document.body, i) + if j == -1: + document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.") + i = i + 1 + continue + k = find_token(document.body, " groupId", i, j) + if k == -1: + i = i + 1 + continue + del document.body[k] + i = i + 1 + + +def update_apa_styles(document): + ' Replace obsolete styles ' + + if document.textclass != "apa": + return + + obsoletedby = { "Acknowledgments": "Acknowledgements", + "Section*": "Section", + "Subsection*": "Subsection", + "Subsubsection*": "Subsubsection", + "Paragraph*": "Paragraph", + "Subparagraph*": "Subparagraph"} + i = 0 + while 1: + i = find_token(document.body, "\\begin_layout", i) + if i == -1: + return + + layout = document.body[i][14:] + if layout in obsoletedby: + document.body[i] = "\\begin_layout " + obsoletedby[layout] + + i += 1 + + +def convert_paper_sizes(document): + ' exchange size options legalpaper and executivepaper to correct order ' + # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868 + i = 0 + j = 0 + i = find_token(document.header, "\\papersize executivepaper", 0) + if i != -1: + document.header[i] = "\\papersize legalpaper" + return + j = find_token(document.header, "\\papersize legalpaper", 0) + if j != -1: + document.header[j] = "\\papersize executivepaper" + + +def revert_paper_sizes(document): + ' exchange size options legalpaper and executivepaper to correct order ' + i = 0 + j = 0 + i = find_token(document.header, "\\papersize executivepaper", 0) + if i != -1: + document.header[i] = "\\papersize legalpaper" + return + j = find_token(document.header, "\\papersize legalpaper", 0) + if j != -1: + document.header[j] = "\\papersize executivepaper" + + +def convert_InsetSpace(document): + " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'" + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Space", i) + if i == -1: + return + document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space') + + +def revert_InsetSpace(document): + " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'" + i = 0 + while True: + i = find_token(document.body, "\\begin_inset space", i) + if i == -1: + return + document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space') + + +def convert_display_enum(document): + " Convert 'display foo' to 'display false/true'" + i = 0 + while True: + i = find_token(document.body, "\tdisplay", i) + if i == -1: + return + val = get_value(document.body, 'display', i) + if val == "none": + document.body[i] = document.body[i].replace('none', 'false') + if val == "default": + document.body[i] = document.body[i].replace('default', 'true') + if val == "monochrome": + document.body[i] = document.body[i].replace('monochrome', 'true') + if val == "grayscale": + document.body[i] = document.body[i].replace('grayscale', 'true') + if val == "color": + document.body[i] = document.body[i].replace('color', 'true') + if val == "preview": + document.body[i] = document.body[i].replace('preview', 'true') + i += 1 + + +def revert_display_enum(document): + " Revert 'display false/true' to 'display none/color'" + i = 0 + while True: + i = find_token(document.body, "\tdisplay", i) + if i == -1: + return + val = get_value(document.body, 'display', i) + if val == "false": + document.body[i] = document.body[i].replace('false', 'none') + if val == "true": + document.body[i] = document.body[i].replace('true', 'default') + i += 1 + + +def remove_fontsCJK(document): + ' Remove font_cjk param ' + i = find_token(document.header, "\\font_cjk", 0) + if i != -1: + del document.header[i] + + +def convert_plain_layout(document): + " Convert 'PlainLayout' to 'Plain Layout'" + i = 0 + while True: + i = find_token(document.body, '\\begin_layout PlainLayout', i) + if i == -1: + return + document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \ + '\\begin_layout Plain Layout') + i += 1 + + +def revert_plain_layout(document): + " Convert 'PlainLayout' to 'Plain Layout'" + i = 0 + while True: + i = find_token(document.body, '\\begin_layout Plain Layout', i) + if i == -1: + return + document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \ + '\\begin_layout PlainLayout') + i += 1 + + +def revert_plainlayout(document): + " Convert 'PlainLayout' to 'Plain Layout'" + i = 0 + while True: + i = find_token(document.body, '\\begin_layout PlainLayout', i) + if i == -1: + return + # This will be incorrect for some document classes, since Standard is not always + # the default. But (a) it is probably the best we can do and (b) it will actually + # work, in fact, since an unknown layout will be converted to default. + document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \ + '\\begin_layout Standard') + i += 1 + + +def revert_polytonicgreek(document): + "Set language polytonic Greek to Greek" + i = 0 + if document.language == "polutonikogreek": + document.language = "greek" + i = find_token(document.header, "\\language", 0) + if i != -1: + document.header[i] = "\\language greek" + j = 0 + while True: + j = find_token(document.body, "\\lang polutonikogreek", j) + if j == -1: + return + document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek") + 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') + + +def revert_backref_options(document): + ' Revert option pdf_backref=page to pagebackref ' + i = find_token(document.header, "\\pdf_backref page", 0) + if i != -1: + document.header[i] = "\\pdf_pagebackref true" + + +def convert_backref_options(document): + ' We have changed the option pagebackref to backref=true ' + i = find_token(document.header, "\\pdf_pagebackref true", 0) + if i != -1: + document.header[i] = "\\pdf_backref page" + j = find_token(document.header, "\\pdf_pagebackref false", 0) + if j != -1: + del document.header[j] + # backref=true was not a valid option, we meant backref=section + k = find_token(document.header, "\\pdf_backref true", 0) + if k != -1 and i != -1: + del document.header[k] + elif k != -1 and j != -1: + document.header[k] = "\\pdf_backref section" + + +def convert_charstyle_element(document): + "Convert CharStyle to Element for docbook backend" + if document.backend != "docbook": + return + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Flex CharStyle:", i) + if i == -1: + return + document.body[i] = document.body[i].replace('\\begin_inset Flex CharStyle:', + '\\begin_inset Flex Element:') + +def revert_charstyle_element(document): + "Convert Element to CharStyle for docbook backend" + if document.backend != "docbook": + return + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Flex Element:", i) + if i == -1: + return + document.body[i] = document.body[i].replace('\\begin_inset Flex Element:', + '\\begin_inset Flex CharStyle:') + +## +# Conversion hub +# + +supported_versions = ["1.6.0","1.6"] +convert = [[277, [fix_wrong_tables]], + [278, [close_begin_deeper]], + [279, [long_charstyle_names]], + [280, [axe_show_label]], + [281, []], + [282, []], + [283, [convert_flex]], + [284, []], + [285, []], + [286, []], + [287, [convert_wrapfig_options]], + [288, [convert_inset_command]], + [289, [convert_latexcommand_index]], + [290, []], + [291, []], + [292, [convert_japanese_cjk]], + [293, []], + [294, [convert_pdf_options]], + [295, [convert_htmlurl, convert_url]], + [296, [convert_include]], + [297, [convert_usorbian]], + [298, [convert_macro_global]], + [299, []], + [300, []], + [301, []], + [302, []], + [303, [convert_serbocroatian]], + [304, [convert_framed_notes]], + [305, []], + [306, []], + [307, []], + [308, []], + [309, []], + [310, []], + [311, [convert_ams_classes]], + [312, []], + [313, [convert_module_names]], + [314, []], + [315, []], + [316, [convert_subfig]], + [317, []], + [318, []], + [319, [convert_spaceinset, convert_hfill]], + [320, []], + [321, [convert_tablines]], + [322, [convert_plain_layout]], + [323, [convert_pagebreaks]], + [324, [convert_linebreaks]], + [325, [convert_japanese_plain]], + [326, []], + [327, []], + [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]], + [329, []], + [330, []], + [331, [convert_ltcaption]], + [332, []], + [333, [update_apa_styles]], + [334, [convert_paper_sizes]], + [335, [convert_InsetSpace]], + [336, []], + [337, [convert_display_enum]], + [338, []], + [339, []], + [340, [add_plain_layout]], + [341, []], + [342, []], + [343, [convert_default_options]], + [344, [convert_backref_options]], + [345, [convert_charstyle_element]] + ] + +revert = [[344, [revert_charstyle_element]], + [343, [revert_backref_options]], + [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]], + [333, [revert_paper_sizes]], + [332, []], + [331, [revert_graphics_group]], + [330, [revert_ltcaption]], + [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]], + [328, [revert_master]], + [327, []], + [326, [revert_mexican]], + [325, [revert_pdfpages]], + [324, []], + [323, [revert_linebreaks]], + [322, [revert_pagebreaks]], + [321, [revert_local_layout, revert_plain_layout]], + [320, [revert_tablines]], + [319, [revert_protected_hfill]], + [318, [revert_spaceinset, revert_hfills, revert_hspace]], + [317, [remove_extra_embedded_files]], + [316, [revert_wrapplacement]], + [315, [revert_subfig]], + [314, [revert_colsep, revert_plainlayout]], + [313, []], + [312, [revert_module_names]], + [311, [revert_rotfloat, revert_widesideways]], + [310, [revert_external_embedding]], + [309, [revert_btprintall]], + [308, [revert_nocite]], + [307, [revert_serbianlatin]], + [306, [revert_slash, revert_nobreakdash]], + [305, [revert_interlingua]], + [304, [revert_bahasam]], + [303, [revert_framed_notes]], + [302, []], + [301, [revert_latin, revert_samin]], + [300, [revert_linebreak]], + [299, [revert_pagebreak]], + [298, [revert_hyperlinktype]], + [297, [revert_macro_optional_params]], + [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]], + [295, [revert_include]], + [294, [revert_href, revert_url]], + [293, [revert_pdf_options_2]], + [292, [revert_inset_info]], + [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]], + [290, [revert_vietnamese]], + [289, [revert_wraptable]], + [288, [revert_latexcommand_index]], + [287, [revert_inset_command]], + [286, [revert_wrapfig_options]], + [285, [revert_pdf_options]], + [284, [remove_inzip_options]], + [283, []], + [282, [revert_flex]], + [281, []], + [280, [revert_begin_modules]], + [279, [revert_show_label]], + [278, [revert_long_charstyle_names]], + [277, []], + [276, []] + ] + + +if __name__ == "__main__": + pass diff --git a/lib/lyx2lyx/parser_tools.py b/lib/lyx2lyx/parser_tools.py index a2fea7af09..9b63e00fd1 100644 --- a/lib/lyx2lyx/parser_tools.py +++ b/lib/lyx2lyx/parser_tools.py @@ -156,6 +156,27 @@ def get_value(lines, token, start, end = 0, default = ""): return default +def get_value_string(lines, token, start, end = 0, trim = False, default = ""): + """ get_value_string(lines, token, start[[, end], trim, default]) -> string + + Return tokens after token as string, in lines, where + token is the first element. When trim is used, the first and last character + of the string is trimmed.""" + + i = find_token_exact(lines, token, start, end) + if i == -1: + return default + if len(lines[i].split()) > 1: + for k in range (0, len(lines[i])): + if lines[i][k] == ' ': + if trim ==False: + return lines[i][k+1:len(lines[i])] + else: + return lines[i][k+2:len(lines[i])-1] + else: + return default + + def del_token(lines, token, start, end): """ del_token(lines, token, start, end) -> int diff --git a/lib/lyx2lyx/profiling.py b/lib/lyx2lyx/profiling.py index b97bc22d1b..fbdb10a2c7 100755 --- a/lib/lyx2lyx/profiling.py +++ b/lib/lyx2lyx/profiling.py @@ -35,11 +35,10 @@ Example: ./profiling.py -ou.lyx ../doc/UserGuide.lyx """ -def main(argv): +def main(): # This will only work with python >= 2.2, the version where this module was added prof = hotshot.Profile("lyx2lyx.prof") # Use temporary file, here? - benchtime = prof.runcall( - lambda : lyx2lyx.main(argv)) + benchtime = prof.runcall(lyx2lyx.main) prof.close() # After the tests, show the profile analysis. @@ -52,4 +51,4 @@ def main(argv): if __name__ == "__main__": - main(sys.argv) + main() diff --git a/status.15x b/status.15x index 294f1156ad..32d71e905c 100644 --- a/status.15x +++ b/status.15x @@ -22,6 +22,12 @@ What's new ** Updates: *********** +* IMPORTING LyX 1.6.x DOCUMENTS + +- The lyx2lyx framework has been updated to be the same as LyX 1.6.0. + This means that now all documents from version 1.6.x can be imported + directly. + * DOCUMENTATION AND LOCALIZATION - Updated localization of the user interface for Catalan, Czech, French, @@ -136,7 +142,7 @@ What's new - Fix LaTeX errors in Latvian and Lithuanian documents (bug 5323, bug 5324). -- If "Do not use amsmath" is selected in the document settings, really do +- If "Do not use amsmath" is selected in the document settings, really do not use it (bug 5350). - Fix the output of IPA symbols with the encoding "utf8".