X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ftex2lyx%2FPreamble.cpp;h=4dc363b5e1c563cf14d9c05aab19cfdbb3b7ebf7;hb=02b6586ad7f8631dfd8001e75779baeb7985c80e;hp=e381af444d1ce9859bbca5f37e9766d8484298de;hpb=18d18f1b8c1506c4d8c8528ea53545e2c15948dc;p=lyx.git diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index e381af444d..4dc363b5e1 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -40,34 +40,28 @@ namespace lyx { // special columntypes extern map special_columns; -const char * const modules_placeholder = "\001modules\001"; - Preamble preamble; namespace { -//add this to known_languages when updating to lyxformat 266: -// "armenian" (needs special handling since not supported by standard babel) -//add these to known_languages when updating to lyxformat 268: -//"chinese-simplified", "chinese-traditional", "japanese", "korean" -// Both changes require first that support for non-babel languages (CJK, -// armtex) is added. +// "chinese-simplified", "chinese-traditional", "japanese-cjk", "korean" +// cannot be supported because it is impossible to determine the correct document +// language if CJK is used. /** * known babel language names (including synonyms) * not in standard babel: arabic, arabtex, armenian, belarusian, serbian-latin, thai - * not yet supported by LyX: kurmanji * please keep this in sync with known_coded_languages line by line! */ const char * const known_languages[] = {"acadian", "afrikaans", "albanian", -"american", "arabic", "arabtex", "austrian", "bahasa", "bahasai", "bahasam", -"basque", "belarusian", "brazil", "brazilian", "breton", "british", "bulgarian", -"canadian", "canadien", "catalan", "croatian", "czech", "danish", "dutch", -"english", "esperanto", "estonian", "farsi", "finnish", "francais", "french", -"frenchb", "frenchle", "frenchpro", "galician", "german", "germanb", "greek", -"hebrew", "hungarian", "icelandic", "indon", "indonesian", "interlingua", -"irish", "italian", "kazakh", "latin", "latvian", "lithuanian", "lowersorbian", -"lsorbian", "magyar", "malay", "meyalu", "mongolian", "naustrian", "newzealand", -"ngerman", "ngermanb", "norsk", "nynorsk", "polutonikogreek", "polish", +"american", "arabic", "arabtex", "australian", "austrian", "bahasa", "bahasai", +"bahasam", "basque", "belarusian", "brazil", "brazilian", "breton", "british", +"bulgarian", "canadian", "canadien", "catalan", "croatian", "czech", "danish", +"dutch", "english", "esperanto", "estonian", "farsi", "finnish", "francais", +"french", "frenchb", "frenchle", "frenchpro", "galician", "german", "germanb", +"greek", "hebrew", "hungarian", "icelandic", "indon", "indonesian", "interlingua", +"irish", "italian", "japanese", "kazakh", "kurmanji", "latin", "latvian", "lithuanian", +"lowersorbian", "lsorbian", "magyar", "malay", "meyalu", "mongolian", "naustrian", +"newzealand", "ngerman", "ngermanb", "norsk", "nynorsk", "polutonikogreek", "polish", "portuges", "portuguese", "romanian", "russian", "russianb", "samin", "scottish", "serbian", "serbian-latin", "slovak", "slovene", "spanish", "swedish", "thai", "turkish", "turkmen", "ukraineb", "ukrainian", @@ -79,15 +73,15 @@ const char * const known_languages[] = {"acadian", "afrikaans", "albanian", * please keep this in sync with known_languages line by line! */ const char * const known_coded_languages[] = {"french", "afrikaans", "albanian", -"american", "arabic_arabi", "arabic_arabtex", "austrian", "bahasa", "bahasa", "bahasam", -"basque", "belarusian", "brazilian", "brazilian", "breton", "british", "bulgarian", -"canadian", "canadien", "catalan", "croatian", "czech", "danish", "dutch", -"english", "esperanto", "estonian", "farsi", "finnish", "french", "french", -"french", "french", "french", "galician", "german", "german", "greek", -"hebrew", "magyar", "icelandic", "bahasa", "bahasa", "interlingua", -"irish", "italian", "kazakh", "latin", "latvian", "lithuanian", "lowersorbian", -"lowersorbian", "magyar", "bahasam", "bahasam", "mongolian", "naustrian", "english", -"ngerman", "ngerman", "norsk", "nynorsk", "polutonikogreek", "polish", +"american", "arabic_arabi", "arabic_arabtex", "australian", "austrian", "bahasa", "bahasa", +"bahasam", "basque", "belarusian", "brazilian", "brazilian", "breton", "british", +"bulgarian", "canadian", "canadien", "catalan", "croatian", "czech", "danish", +"dutch", "english", "esperanto", "estonian", "farsi", "finnish", "french", +"french", "french", "french", "french", "galician", "german", "german", +"greek", "hebrew", "magyar", "icelandic", "bahasa", "bahasa", "interlingua", +"irish", "italian", "japanese", "kazakh", "kurmanji", "latin", "latvian", "lithuanian", +"lowersorbian", "lowersorbian", "magyar", "bahasam", "bahasam", "mongolian", "naustrian", +"newzealand", "ngerman", "ngerman", "norsk", "nynorsk", "polutonikogreek", "polish", "portuguese", "portuguese", "romanian", "russian", "russian", "samin", "scottish", "serbian", "serbian-latin", "slovak", "slovene", "spanish", "swedish", "thai", "turkish", "turkmen", "ukrainian", "ukrainian", @@ -95,9 +89,10 @@ const char * const known_coded_languages[] = {"french", "afrikaans", "albanian", 0}; /// languages with english quotes (.lyx names) -const char * const known_english_quotes_languages[] = {"american", "bahasa", -"bahasam", "brazilian", "canadian", "chinese-simplified", "english", -"esperanto", "hebrew", "irish", "korean", "portuguese", "scottish", "thai", 0}; +const char * const known_english_quotes_languages[] = {"american", "australian", +"bahasa", "bahasam", "brazilian", "canadian", "chinese-simplified", "english", +"esperanto", "hebrew", "irish", "korean", "newzealand", "portuguese", "scottish", +"thai", 0}; /// languages with french quotes (.lyx names) const char * const known_french_quotes_languages[] = {"albanian", @@ -145,7 +140,7 @@ const char * const known_paper_sizes[] = { "a0paper", "b0paper", "c0paper", const char * const known_class_paper_sizes[] = { "a4paper", "a5paper", "executivepaper", "legalpaper", "letterpaper", 0}; -const char * const known_paper_margins[] = { "lmargin", "tmargin", "rmargin", +const char * const known_paper_margins[] = { "lmargin", "tmargin", "rmargin", "bmargin", "headheight", "headsep", "footskip", "columnsep", 0}; const char * const known_coded_paper_margins[] = { "leftmargin", "topmargin", @@ -167,6 +162,26 @@ const char * const known_basic_color_codes[] = {"#0000ff", "#000000", "#00ffff", const char * const known_if_3arg_commands[] = {"@ifundefined", "IfFileExists", 0}; +/// packages that work only in xetex +/// polyglossia is handled separately +const char * const known_xetex_packages[] = {"arabxetex", "fixlatvian", +"fontbook", "fontwrap", "mathspec", "philokalia", "unisugar", +"xeCJK", "xecolor", "xecyr", "xeindex", "xepersian", "xunicode", 0}; + +/// packages that are automatically skipped if loaded by LyX +const char * const known_lyx_packages[] = {"amsbsy", "amsmath", "amssymb", +"amstext", "amsthm", "array", "babel", "booktabs", "calc", "CJK", "color", "float", +"fontspec", "graphicx", "hhline", "ifthen", "longtable", "makeidx", "multirow", +"nomencl", "pdfpages", "rotating", "rotfloat", "splitidx", "setspace", +"subscript", "textcomp", "ulem", "url", "varioref", "verbatim", "wrapfig", +"xunicode", 0}; + +// codes used to remove packages that are loaded automatically by LyX. +// Syntax: package_beg_seppackage_mid_seppackage_end_sep +const char package_beg_sep = '\001'; +const char package_mid_sep = '\002'; +const char package_end_sep = '\003'; + // returns true if at least one of the options in what has been found bool handle_opt(vector & opts, char const * const * what, string & target) @@ -267,6 +282,42 @@ string process_keyval_opt(vector & options, string name) } // anonymous namespace +/** + * known polyglossia language names (including variants) + */ +const char * const Preamble::polyglossia_languages[] = { +"albanian", "croatian", "hebrew", "norsk", "swedish", "amharic", "czech", "hindi", +"nynorsk", "syriac", "arabic", "danish", "icelandic", "occitan", "tamil", +"armenian", "divehi", "interlingua", "polish", "telugu", "asturian", "dutch", +"irish", "portuges", "thai", "bahasai", "english", "italian", "romanian", "turkish", +"bahasam", "esperanto", "lao", "russian", "turkmen", "basque", "estonian", "latin", +"samin", "ukrainian", "bengali", "farsi", "latvian", "sanskrit", "urdu", "brazil", +"brazilian", "finnish", "lithuanian", "scottish", "usorbian", "breton", "french", +"lsorbian", "serbian", "vietnamese", "bulgarian", "galician", "magyar", "slovak", +"welsh", "catalan", "german", "malayalam", "slovenian", "coptic", "greek", +"marathi", "spanish", +"american", "ancient", "australian", "british", "monotonic", "newzealand", +"polytonic", 0}; + +/** + * the same as polyglossia_languages with .lyx names + * please keep this in sync with polyglossia_languages line by line! + */ +const char * const Preamble::coded_polyglossia_languages[] = { +"albanian", "croatian", "hebrew", "norsk", "swedish", "amharic", "czech", "hindi", +"nynorsk", "syriac", "arabic_arabi", "danish", "icelandic", "occitan", "tamil", +"armenian", "divehi", "interlingua", "polish", "telugu", "asturian", "dutch", +"irish", "portuges", "thai", "bahasa", "english", "italian", "romanian", "turkish", +"bahasam", "esperanto", "lao", "russian", "turkmen", "basque", "estonian", "latin", +"samin", "ukrainian", "bengali", "farsi", "latvian", "sanskrit", "urdu", "brazilian", +"brazilian", "finnish", "lithuanian", "scottish", "uppersorbian", "breton", "french", +"lowersorbian", "serbian", "vietnamese", "bulgarian", "galician", "magyar", "slovak", +"welsh", "catalan", "ngerman", "malayalam", "slovene", "coptic", "greek", +"marathi", "spanish", +"american", "ancientgreek", "australian", "british", "greek", "newzealand", +"polutonikogreek", 0}; + + bool Preamble::indentParagraphs() const { return h_paragraph_separation == "indent"; @@ -288,9 +339,46 @@ vector Preamble::getPackageOptions(string const & package) const } -string Preamble::addModules(string const & lyxpreamble, string const & modules) +void Preamble::registerAutomaticallyLoadedPackage(std::string const & package) +{ + auto_packages.insert(package); +} + + +void Preamble::addModule(string const & module) +{ + used_modules.push_back(module); +} + + +void Preamble::suppressDate(bool suppress) +{ + if (suppress) + h_suppress_date = "true"; + else + h_suppress_date = "false"; +} + + +void Preamble::registerAuthor(std::string const & name) +{ + Author author(from_utf8(name), empty_docstring()); + author.setUsed(true); + authors_.record(author); + h_tracking_changes = "true"; + h_output_changes = "true"; +} + + +Author const & Preamble::getAuthor(std::string const & name) const { - return subst(lyxpreamble, modules_placeholder, modules); + Author author(from_utf8(name), empty_docstring()); + for (AuthorList::Authors::const_iterator it = authors_.begin(); + it != authors_.end(); ++it) + if (*it == author) + return *it; + static Author const dummy; + return dummy; } @@ -342,11 +430,15 @@ string remove_braces(string const & value) } // anonymous namespace -Preamble::Preamble() : one_language(true), ifundefined_color_set(false) +Preamble::Preamble() : one_language(true), title_layout_found(false) { //h_backgroundcolor; //h_boxbgcolor; + h_biblio_style = "plain"; + h_bibtex_command = "default"; h_cite_engine = "basic"; + h_cite_engine_type = "numerical"; + h_color = "#008000"; h_defskip = "medskip"; //h_float_placement; //h_fontcolor; @@ -355,22 +447,30 @@ Preamble::Preamble() : one_language(true), ifundefined_color_set(false) h_font_sans = "default"; h_font_typewriter = "default"; h_font_default_family = "default"; + h_use_non_tex_fonts = "false"; h_font_sc = "false"; h_font_osf = "false"; h_font_sf_scale = "100"; h_font_tt_scale = "100"; h_graphics = "default"; + h_default_output_format = "default"; h_html_be_strict = "false"; h_html_css_as_file = "0"; h_html_math_output = "0"; + h_index = "Index"; + h_index_command = "default"; h_inputencoding = "auto"; + h_justification = "true"; h_language = "english"; h_language_package = "none"; //h_listings_params; + h_maintain_unincluded_children = "false"; //h_margins; //h_notefontcolor; //h_options; h_output_changes = "false"; + h_output_sync = "0"; + //h_output_sync_macro h_papercolumns = "1"; h_paperfontsize = "default"; h_paperorientation = "portrait"; @@ -396,21 +496,25 @@ Preamble::Preamble() : one_language(true), ifundefined_color_set(false) //h_pdf_quoted_options; h_quotes_language = "english"; h_secnumdepth = "3"; + h_shortcut = "idx"; h_spacing = "single"; h_suppress_date = "false"; h_textclass = "article"; h_tocdepth = "3"; h_tracking_changes = "false"; h_use_bibtopic = "false"; + h_use_indices = "false"; h_use_geometry = "false"; - h_use_amsmath = "1"; h_use_default_options = "false"; - h_use_esint = "1"; h_use_hyperref = "0"; - h_use_mhchem = "0"; - h_use_mathdots = "0"; - h_use_refstyle = "0"; - h_use_undertilde = "0"; + h_use_refstyle = "1"; + h_use_packages["amsmath"] = "1"; + h_use_packages["amssymb"] = "1"; + h_use_packages["esint"] = "1"; + h_use_packages["mhchem"] = "1"; + h_use_packages["mathdots"] = "1"; + h_use_packages["mathtools"] = "1"; + h_use_packages["undertilde"] = "1"; } @@ -498,6 +602,36 @@ void Preamble::handle_hyperref(vector & options) } +void Preamble::handle_geometry(vector & options) +{ + h_use_geometry = "true"; + vector::iterator it; + // paper orientation + if ((it = find(options.begin(), options.end(), "landscape")) != options.end()) { + h_paperorientation = "landscape"; + options.erase(it); + } + // paper size + // keyval version: "paper=letter" + string paper = process_keyval_opt(options, "paper"); + if (!paper.empty()) + h_papersize = paper + "paper"; + // alternative version: "letterpaper" + handle_opt(options, known_paper_sizes, h_papersize); + delete_opt(options, known_paper_sizes); + // page margins + char const * const * margin = known_paper_margins; + for (; *margin; ++margin) { + string value = process_keyval_opt(options, *margin); + if (!value.empty()) { + int k = margin - known_paper_margins; + string name = known_coded_paper_margins[k]; + h_margins += '\\' + name + ' ' + value + '\n'; + } + } +} + + void Preamble::handle_package(Parser &p, string const & name, string const & opts, bool in_lyx_preamble) { @@ -505,6 +639,14 @@ void Preamble::handle_package(Parser &p, string const & name, add_package(name, options); string scale; + if (is_known(name, known_xetex_packages)) { + xetex = true; + h_use_non_tex_fonts = "true"; + registerAutomaticallyLoadedPackage("fontspec"); + if (h_inputencoding == "auto") + p.setEncoding("utf8"); + } + // roman fonts if (is_known(name, known_roman_fonts)) { h_font_roman = name; @@ -518,10 +660,10 @@ void Preamble::handle_package(Parser &p, string const & name, h_font_sc = "true"; } - if (name == "mathpazo") + else if (name == "mathpazo") h_font_roman = "palatino"; - if (name == "mathptmx") + else if (name == "mathptmx") h_font_roman = "times"; // sansserif fonts @@ -556,20 +698,10 @@ void Preamble::handle_package(Parser &p, string const & name, || is_known(name, known_typewriter_fonts)) ; - else if (name == "amsmath" || name == "amssymb") - h_use_amsmath = "2"; - - else if (name == "esint") - h_use_esint = "2"; - - else if (name == "mhchem") - h_use_mhchem = "2"; - - else if (name == "mathdots") - h_use_mathdots = "2"; - - else if (name == "undertilde") - h_use_undertilde = "2"; + else if (name == "amsmath" || name == "amssymb" || + name == "esint" || name == "mhchem" || name == "mathdots" || + name == "mathtools" || name == "undertilde") + h_use_packages[name] = "2"; else if (name == "babel") { h_language_package = "default"; @@ -580,24 +712,55 @@ void Preamble::handle_package(Parser &p, string const & name, // we need to keep it in the preamble to prevent cases like bug #7861. if (!opts.empty()) { // check if more than one option was used - used later for inputenc - // in case inputenc is parsed before babel, set the encoding to auto if (options.begin() != options.end() - 1) one_language = false; // babel takes the last language of the option of its \usepackage // call as document language. If there is no such language option, the // last language in the documentclass options is used. handle_opt(options, known_languages, h_language); - // If babel is called with options, LyX puts them by default into the - // document class options. This works for most languages, except - // for Latvian, Lithuanian, Mongolian, Turkmen and Vietnamese and - // perhaps in future others. - // Therefore keep the babel call as it is as the user might have - // reasons for it. - h_preamble << "\\usepackage[" << opts << "]{babel}\n"; + // translate the babel name to a LyX name + h_language = babel2lyx(h_language); + // for Japanese we assume EUC-JP as encoding + // but we cannot determine the exact encoding and thus output also a note + if (h_language == "japanese") { + h_inputencoding = "euc"; + p.setEncoding("EUC-JP"); + is_nonCJKJapanese = true; + // in this case babel can be removed from the preamble + registerAutomaticallyLoadedPackage("babel"); + } else { + // If babel is called with options, LyX puts them by default into the + // document class options. This works for most languages, except + // for Latvian, Lithuanian, Mongolian, Turkmen and Vietnamese and + // perhaps in future others. + // Therefore keep the babel call as it is as the user might have + // reasons for it. + h_preamble << "\\usepackage[" << opts << "]{babel}\n"; + } delete_opt(options, known_languages); } else - h_preamble << "\\usepackage{babel}\n"; + h_preamble << "\\usepackage{babel}\n"; + } + + else if (name == "polyglossia") { + h_language_package = "default"; + h_default_output_format = "pdf4"; + h_use_non_tex_fonts = "true"; + xetex = true; + registerAutomaticallyLoadedPackage("xunicode"); + if (h_inputencoding == "auto") + p.setEncoding("utf8"); + } + + else if (name == "CJK") { + // It is impossible to determine the document language if CJK is used. + // All we can do is to notify the user that he has to set this by himself. + have_CJK = true; + // set the encoding to "auto" because it might be set to "default" by the babel handling + // and this would not be correct for CJK + h_inputencoding = "auto"; + registerAutomaticallyLoadedPackage("CJK"); } else if (name == "fontenc") { @@ -615,8 +778,8 @@ void Preamble::handle_package(Parser &p, string const & name, // inputenc option because otherwise h_inputencoding must be // set to "auto" (the default encoding of the document language) // Therefore check for the "," character. - // It is also only set when there is not more then one babel - // language option but this is handled in the routine for babel. + // It is also only set when there is not more than one babel + // language option. if (opts.find(",") == string::npos && one_language == true) h_inputencoding = opts; if (!options.empty()) @@ -624,76 +787,53 @@ void Preamble::handle_package(Parser &p, string const & name, options.clear(); } + else if (name == "srcltx") { + h_output_sync = "1"; + if (!opts.empty()) { + h_output_sync_macro = "\\usepackage[" + opts + "]{srcltx}"; + options.clear(); + } else + h_output_sync_macro = "\\usepackage{srcltx}"; + } + else if (is_known(name, known_old_language_packages)) { // known language packages from the times before babel // if they are found and not also babel, they will be used as - // cutom language package + // custom language package h_language_package = "\\usepackage{" + name + "}"; } - else if (name == "makeidx") - ; // ignore this - else if (name == "prettyref") - ; // ignore this - - else if (name == "varioref") - ; // ignore this + ; // ignore this FIXME: Use the package separator mechanism instead - else if (name == "verbatim") - ; // ignore this - - else if (name == "nomencl") - ; // ignore this - - else if (name == "textcomp") - ; // ignore this - - else if (name == "url") - ; // ignore this - - else if (name == "subscript") - ; // ignore this - - else if (name == "color") { - // with the following command this package is only loaded when needed for - // undefined colors, since we only support the predefined colors - // only add it if not yet added - if (!ifundefined_color_set) - h_preamble << "\\@ifundefined{definecolor}\n {\\usepackage{color}}{}\n"; + else if (name == "lyxskak") { + // ignore this and its options + const char * const o[] = {"ps", "mover", 0}; + delete_opt(options, o); } - else if (name == "graphicx") - ; // ignore this - - else if (name == "setspace") - ; // ignore this - -#if 0 - // do not ignore as long as we don't support all commands (e.g. \xout is missing) - // and as long as we don't support change tracking - else if (name == "ulem") - ; // ignore this -#endif + else if (is_known(name, known_lyx_packages) && options.empty()) { + if (name == "splitidx") + h_use_indices = "true"; + if (!in_lyx_preamble) + h_preamble << package_beg_sep << name + << package_mid_sep << "\\usepackage{" + << name << "}\n" << package_end_sep; + } else if (name == "geometry") - ; // Ignore this, the geometry settings are made by the \geometry - // command. This command is handled below. - - else if (name == "rotfloat") - ; // ignore this - - else if (name == "wrapfig") - ; // ignore this + handle_geometry(options); else if (name == "subfig") - ; // ignore this + ; // ignore this FIXME: Use the package separator mechanism instead else if (is_known(name, known_languages)) h_language = name; else if (name == "natbib") { - h_cite_engine = "natbib_authoryear"; + h_biblio_style = "plainnat"; + h_cite_engine = "natbib"; + h_cite_engine_type = "authoryear"; vector::iterator it = find(options.begin(), options.end(), "authoryear"); if (it != options.end()) @@ -701,24 +841,27 @@ void Preamble::handle_package(Parser &p, string const & name, else { it = find(options.begin(), options.end(), "numbers"); if (it != options.end()) { - h_cite_engine = "natbib_numerical"; + h_cite_engine_type = "numerical"; options.erase(it); } } } - else if (name == "jurabib") + else if (name == "jurabib") { + h_biblio_style = "jurabib"; h_cite_engine = "jurabib"; + h_cite_engine_type = "authoryear"; + } else if (name == "hyperref") handle_hyperref(options); else if (!in_lyx_preamble) { if (options.empty()) - h_preamble << "\\usepackage{" << name << "}"; + h_preamble << "\\usepackage{" << name << "}\n"; else { - h_preamble << "\\usepackage[" << opts << "]{" - << name << "}"; + h_preamble << "\\usepackage[" << opts << "]{" + << name << "}\n"; options.clear(); } } @@ -750,11 +893,8 @@ void Preamble::handle_if(Parser & p, bool in_lyx_preamble) } -void Preamble::end_preamble(ostream & os, TeX2LyXDocClass const & /*tc*/) +bool Preamble::writeLyXHeader(ostream & os, bool subdoc) { - // translate from babel to LyX names - h_language = babel2lyx(h_language); - // set the quote language // LyX only knows the following quotes languages: // english, swedish, german, polish, french and danish @@ -782,18 +922,58 @@ void Preamble::end_preamble(ostream & os, TeX2LyXDocClass const & /*tc*/) else if (is_known(h_language, known_english_quotes_languages)) h_quotes_language = "english"; + if (contains(h_float_placement, "H")) + registerAutomaticallyLoadedPackage("float"); + if (h_spacing != "single" && h_spacing != "default") + registerAutomaticallyLoadedPackage("setspace"); + if (h_use_packages["amsmath"] == "2") { + // amsbsy and amstext are already provided by amsmath + registerAutomaticallyLoadedPackage("amsbsy"); + registerAutomaticallyLoadedPackage("amstext"); + } + // output the LyX file settings os << "#LyX file created by tex2lyx " << PACKAGE_VERSION << "\n" << "\\lyxformat " << LYX_FORMAT << '\n' << "\\begin_document\n" << "\\begin_header\n" << "\\textclass " << h_textclass << "\n"; - if (!h_preamble.str().empty()) - os << "\\begin_preamble\n" << h_preamble.str() << "\n\\end_preamble\n"; + string const raw = subdoc ? empty_string() : h_preamble.str(); + if (!raw.empty()) { + os << "\\begin_preamble\n"; + for (string::size_type i = 0; i < raw.size(); ++i) { + if (raw[i] == package_beg_sep) { + // Here follows some package loading code that + // must be skipped if the package is loaded + // automatically. + string::size_type j = raw.find(package_mid_sep, i); + if (j == string::npos) + return false; + string::size_type k = raw.find(package_end_sep, j); + if (k == string::npos) + return false; + string const package = raw.substr(i + 1, j - i - 1); + string const replacement = raw.substr(j + 1, k - j - 1); + if (auto_packages.find(package) == auto_packages.end()) + os << replacement; + i = k; + } else + os.put(raw[i]); + } + os << "\n\\end_preamble\n"; + } if (!h_options.empty()) os << "\\options " << h_options << "\n"; - os << "\\use_default_options " << h_use_default_options << "\n" - << modules_placeholder + os << "\\use_default_options " << h_use_default_options << "\n"; + if (!used_modules.empty()) { + os << "\\begin_modules\n"; + vector::const_iterator const end = used_modules.end(); + vector::const_iterator it = used_modules.begin(); + for (; it != end; ++it) + os << *it << '\n'; + os << "\\end_modules\n"; + } + os << "\\maintain_unincluded_children " << h_maintain_unincluded_children << "\n" << "\\language " << h_language << "\n" << "\\language_package " << h_language_package << "\n" << "\\inputencoding " << h_inputencoding << "\n" @@ -802,11 +982,18 @@ void Preamble::end_preamble(ostream & os, TeX2LyXDocClass const & /*tc*/) << "\\font_sans " << h_font_sans << "\n" << "\\font_typewriter " << h_font_typewriter << "\n" << "\\font_default_family " << h_font_default_family << "\n" + << "\\use_non_tex_fonts " << h_use_non_tex_fonts << "\n" << "\\font_sc " << h_font_sc << "\n" << "\\font_osf " << h_font_osf << "\n" << "\\font_sf_scale " << h_font_sf_scale << "\n" << "\\font_tt_scale " << h_font_tt_scale << "\n" - << "\\graphics " << h_graphics << "\n"; + << "\\graphics " << h_graphics << "\n" + << "\\default_output_format " << h_default_output_format << "\n" + << "\\output_sync " << h_output_sync << "\n"; + if (h_output_sync == "1") + os << "\\output_sync_macro \"" << h_output_sync_macro << "\"\n"; + os << "\\bibtex_command " << h_bibtex_command << "\n" + << "\\index_command " << h_index_command << "\n"; if (!h_float_placement.empty()) os << "\\float_placement " << h_float_placement << "\n"; os << "\\paperfontsize " << h_paperfontsize << "\n" @@ -836,16 +1023,18 @@ void Preamble::end_preamble(ostream & os, TeX2LyXDocClass const & /*tc*/) os << "\\pdf_quoted_options \"" << h_pdf_quoted_options << "\"\n"; } os << "\\papersize " << h_papersize << "\n" - << "\\use_geometry " << h_use_geometry << "\n" - << "\\use_amsmath " << h_use_amsmath << "\n" - << "\\use_esint " << h_use_esint << "\n" - << "\\use_mhchem " << h_use_mhchem << "\n" - << "\\use_mathdots " << h_use_mathdots << "\n" - << "\\use_undertilde " << h_use_undertilde << "\n" - << "\\cite_engine " << h_cite_engine << "\n" + << "\\use_geometry " << h_use_geometry << '\n'; + for (map::const_iterator it = h_use_packages.begin(); + it != h_use_packages.end(); ++it) + os << "\\use_package " << it->first << ' ' << it->second << '\n'; + os << "\\cite_engine " << h_cite_engine << '\n' + << "\\cite_engine_type " << h_cite_engine_type << '\n' + << "\\biblio_style " << h_biblio_style << "\n" << "\\use_bibtopic " << h_use_bibtopic << "\n" + << "\\use_indices " << h_use_indices << "\n" << "\\paperorientation " << h_paperorientation << '\n' << "\\suppress_date " << h_suppress_date << '\n' + << "\\justification " << h_justification << '\n' << "\\use_refstyle " << h_use_refstyle << '\n'; if (!h_fontcolor.empty()) os << "\\fontcolor " << h_fontcolor << '\n'; @@ -855,6 +1044,10 @@ void Preamble::end_preamble(ostream & os, TeX2LyXDocClass const & /*tc*/) os << "\\backgroundcolor " << h_backgroundcolor << '\n'; if (!h_boxbgcolor.empty()) os << "\\boxbgcolor " << h_boxbgcolor << '\n'; + os << "\\index " << h_index << '\n' + << "\\shortcut " << h_shortcut << '\n' + << "\\color " << h_color << '\n' + << "\\end_index\n"; os << h_margins << "\\secnumdepth " << h_secnumdepth << "\n" << "\\tocdepth " << h_tocdepth << "\n" @@ -874,15 +1067,15 @@ void Preamble::end_preamble(ostream & os, TeX2LyXDocClass const & /*tc*/) << "\\html_math_output " << h_html_math_output << "\n" << "\\html_css_as_file " << h_html_css_as_file << "\n" << "\\html_be_strict " << h_html_be_strict << "\n" + << authors_ << "\\end_header\n\n" << "\\begin_body\n"; - // clear preamble for subdocuments - h_preamble.str(""); + return true; } -void Preamble::parse(Parser & p, ostream & os, - string const & forceclass, TeX2LyXDocClass & tc) +void Preamble::parse(Parser & p, string const & forceclass, + TeX2LyXDocClass & tc) { // initialize fixed types special_columns['D'] = 3; @@ -924,7 +1117,7 @@ void Preamble::parse(Parser & p, ostream & os, t.cat() == catParameter)) h_preamble << t.cs(); - else if (!in_lyx_preamble && + else if (!in_lyx_preamble && (t.cat() == catSpace || t.cat() == catNewline)) h_preamble << t.asInput(); @@ -937,7 +1130,7 @@ void Preamble::parse(Parser & p, ostream & os, // magically switch encoding default if it looks like XeLaTeX static string const magicXeLaTeX = "% This document must be compiled with XeLaTeX "; - if (comment.size() > magicXeLaTeX.size() + if (comment.size() > magicXeLaTeX.size() && comment.substr(0, magicXeLaTeX.size()) == magicXeLaTeX && h_inputencoding == "auto") { cerr << "XeLaTeX comment found, switching to UTF8\n"; @@ -957,6 +1150,70 @@ void Preamble::parse(Parser & p, ostream & os, else if (t.cs() == "pagestyle") h_paperpagestyle = p.verbatim_item(); + else if (t.cs() == "setdefaultlanguage") { + xetex = true; + // We don't yet care about non-language variant options + // because LyX doesn't support this yet, see bug #8214 + if (p.hasOpt()) { + string langopts = p.getOpt(); + // check if the option contains a variant, if yes, extract it + string::size_type pos_var = langopts.find("variant"); + string::size_type i = langopts.find(',', pos_var); + string::size_type k = langopts.find('=', pos_var); + if (pos_var != string::npos){ + string variant; + if (i == string::npos) + variant = langopts.substr(k + 1, langopts.length() - k - 2); + else + variant = langopts.substr(k + 1, i - k - 1); + h_language = variant; + } + p.verbatim_item(); + } else + h_language = p.verbatim_item(); + //finally translate the poyglossia name to a LyX name + h_language = polyglossia2lyx(h_language); + } + + else if (t.cs() == "setotherlanguage") { + // We don't yet care about the option because LyX doesn't + // support this yet, see bug #8214 + p.hasOpt() ? p.getOpt() : string(); + p.verbatim_item(); + } + + else if (t.cs() == "setmainfont") { + // we don't care about the option + p.hasOpt() ? p.getOpt() : string(); + h_font_roman = p.getArg('{', '}'); + } + + else if (t.cs() == "setsansfont" || t.cs() == "setmonofont") { + // LyX currently only supports the scale option + string scale; + if (p.hasOpt()) { + string fontopts = p.getArg('[', ']'); + // check if the option contains a scaling, if yes, extract it + string::size_type pos = fontopts.find("Scale"); + if (pos != string::npos) { + string::size_type i = fontopts.find(',', pos); + if (i == string::npos) + scale = scale_as_percentage(fontopts.substr(pos + 1)); + else + scale = scale_as_percentage(fontopts.substr(pos, i - pos)); + } + } + if (t.cs() == "setsansfont") { + if (!scale.empty()) + h_font_sf_scale = scale; + h_font_sans = p.getArg('{', '}'); + } else { + if (!scale.empty()) + h_font_tt_scale = scale; + h_font_typewriter = p.getArg('{', '}'); + } + } + else if (t.cs() == "date") { string argument = p.getArg('{', '}'); if (argument.empty()) @@ -966,15 +1223,22 @@ void Preamble::parse(Parser & p, ostream & os, } else if (t.cs() == "color") { + string const space = + (p.hasOpt() ? p.getOpt() : string()); string argument = p.getArg('{', '}'); // check the case that a standard color is used - if (is_known(argument, known_basic_colors)) - h_fontcolor = color2code(argument); + if (space.empty() && is_known(argument, known_basic_colors)) { + h_fontcolor = rgbcolor2code(argument); + preamble.registerAutomaticallyLoadedPackage("color"); + } else if (space.empty() && argument == "document_fontcolor") + preamble.registerAutomaticallyLoadedPackage("color"); // check the case that LyX's document_fontcolor is defined // but not used for \color - if (argument != "document_fontcolor" - && !is_known(argument, known_basic_colors)) { - h_preamble << t.asInput() << '{' << argument << '}'; + else { + h_preamble << t.asInput(); + if (!space.empty()) + h_preamble << space; + h_preamble << '{' << argument << '}'; // the color might already be set because \definecolor // is parsed before this h_fontcolor = ""; @@ -984,12 +1248,13 @@ void Preamble::parse(Parser & p, ostream & os, else if (t.cs() == "pagecolor") { string argument = p.getArg('{', '}'); // check the case that a standard color is used - if (is_known(argument, known_basic_colors)) - h_backgroundcolor = color2code(argument); + if (is_known(argument, known_basic_colors)) { + h_backgroundcolor = rgbcolor2code(argument); + } else if (argument == "page_backgroundcolor") + preamble.registerAutomaticallyLoadedPackage("color"); // check the case that LyX's page_backgroundcolor is defined // but not used for \pagecolor - if (argument != "page_backgroundcolor" - && !is_known(argument, known_basic_colors)) { + else { h_preamble << t.asInput() << '{' << argument << '}'; // the color might already be set because \definecolor // is parsed before this @@ -1039,6 +1304,11 @@ void Preamble::parse(Parser & p, ostream & os, h_font_default_family = family.erase(0,1); } + // remove the lyxdot definition that is re-added by LyX + // if necessary + if (name == "\\lyxdot") + in_lyx_preamble = true; + // Add the command to the known commands add_known_command(name, opt1, !opt2.empty(), from_utf8(body)); @@ -1102,7 +1372,7 @@ void Preamble::parse(Parser & p, ostream & os, opts.erase(it); } // paper sizes - // some size options are know to any document classes, other sizes + // some size options are known to any document classes, other sizes // are handled by the \geometry command of the geometry package handle_opt(opts, known_class_paper_sizes, h_papersize); delete_opt(opts, known_class_paper_sizes); @@ -1121,7 +1391,7 @@ void Preamble::parse(Parser & p, ostream & os, vector::const_iterator it = vecnames.begin(); vector::const_iterator end = vecnames.end(); for (; it != end; ++it) - handle_package(p, trimSpaceAndEol(*it), options, + handle_package(p, trimSpaceAndEol(*it), options, in_lyx_preamble); } @@ -1149,8 +1419,12 @@ void Preamble::parse(Parser & p, ostream & os, else if (t.cs() == "def") { string name = p.get_token().cs(); + // In fact, name may be more than the name: + // In the test case of bug 8116 + // name == "csname SF@gobble@opt \endcsname". + // Therefore, we need to use asInput() instead of cs(). while (p.next_token().cat() != catBegin) - name += p.get_token().cs(); + name += p.get_token().asInput(); if (!in_lyx_preamble) h_preamble << "\\def\\" << name << '{' << p.verbatim_item() << "}"; @@ -1214,6 +1488,19 @@ void Preamble::parse(Parser & p, ostream & os, else if (t.cs() == "setstretch") h_spacing = "other " + p.verbatim_item(); + else if (t.cs() == "synctex") { + // the scheme is \synctex=value + // where value can only be "1" or "-1" + h_output_sync = "1"; + // there can be any character behind the value (e.g. a linebreak or a '\' + // therefore we extract it char by char + p.get_token(); + string value = p.get_token().asInput(); + if (value == "-") + value += p.get_token().asInput(); + h_output_sync_macro = "\\synctex=" + value; + } + else if (t.cs() == "begin") { string const name = p.getArg('{', '}'); if (name == "document") @@ -1222,32 +1509,8 @@ void Preamble::parse(Parser & p, ostream & os, } else if (t.cs() == "geometry") { - h_use_geometry = "true"; vector opts = split_options(p.getArg('{', '}')); - vector::iterator it; - // paper orientation - if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) { - h_paperorientation = "landscape"; - opts.erase(it); - } - // paper size - handle_opt(opts, known_paper_sizes, h_papersize); - delete_opt(opts, known_paper_sizes); - // page margins - char const * const * margin = known_paper_margins; - int k = -1; - for (; *margin; ++margin) { - k += 1; - // search for the "=" in e.g. "lmargin=2cm" to get the value - for(size_t i = 0; i != opts.size(); i++) { - if (opts.at(i).find(*margin) != string::npos) { - string::size_type pos = opts.at(i).find("="); - string value = opts.at(i).substr(pos + 1); - string name = known_coded_paper_margins[k]; - h_margins += "\\" + name + " " + value + "\n"; - } - } - } + handle_geometry(opts); } else if (t.cs() == "definecolor") { @@ -1273,6 +1536,9 @@ void Preamble::parse(Parser & p, ostream & os, } } + else if (t.cs() == "bibliographystyle") + h_biblio_style = p.verbatim_item(); + else if (t.cs() == "jurabibsetup") { // FIXME p.getArg('{', '}') is most probably wrong (it // does not handle nested braces). @@ -1306,18 +1572,27 @@ void Preamble::parse(Parser & p, ostream & os, string const arg2 = p.verbatim_item(); string const arg3 = p.verbatim_item(); // test case \@ifundefined{date}{}{\date{}} - if (arg1 == "date" && arg2.empty() && arg3 == "\\date{}") { + if (t.cs() == "@ifundefined" && arg1 == "date" && + arg2.empty() && arg3 == "\\date{}") { h_suppress_date = "true"; - // test case \@ifundefined{definecolor}{\usepackage{color}}{} - // because we could pollute the preamble with it in roundtrips - } else if (arg1 == "definecolor" && arg2 == "\\usepackage{color}" - && arg3.empty()) { - ifundefined_color_set = true; + // older tex2lyx versions did output + // \@ifundefined{definecolor}{\usepackage{color}}{} + } else if (t.cs() == "@ifundefined" && + arg1 == "definecolor" && + arg2 == "\\usepackage{color}" && + arg3.empty()) { + if (!in_lyx_preamble) + h_preamble << package_beg_sep + << "color" + << package_mid_sep + << "\\@ifundefined{definecolor}{color}{}" + << package_end_sep; // test for case //\@ifundefined{showcaptionsetup}{}{% // \PassOptionsToPackage{caption=false}{subfig}} // that LyX uses for subfloats - } else if (arg1 == "showcaptionsetup" && arg2.empty() + } else if (t.cs() == "@ifundefined" && + arg1 == "showcaptionsetup" && arg2.empty() && arg3 == "%\n \\PassOptionsToPackage{caption=false}{subfig}") { ; // do nothing } else if (!in_lyx_preamble) { @@ -1358,7 +1633,6 @@ void Preamble::parse(Parser & p, ostream & os, ss << tc.sides(); h_papersides = ss.str(); } - end_preamble(os, tc); } @@ -1371,12 +1645,25 @@ string babel2lyx(string const & language) } -string color2code(string const & name) +string Preamble::polyglossia2lyx(string const & language) { - char const * const * where = is_known(name, known_basic_colors); + char const * const * where = is_known(language, polyglossia_languages); if (where) + return coded_polyglossia_languages[where - polyglossia_languages]; + return language; +} + + +string rgbcolor2code(string const & name) +{ + char const * const * where = is_known(name, known_basic_colors); + if (where) { + // "red", "green" etc return known_basic_color_codes[where - known_basic_colors]; - return name; + } + // "255,0,0", "0,255,0" etc + RGBColor c(RGBColorFromLaTeX(name)); + return X11hexname(c); } // }])