X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ftex2lyx%2FPreamble.cpp;h=e4e10c088e943d44bf7177312b46d495855d6aef;hb=79cf3f5ec1088e7de988e889247ec300d42fb70b;hp=131f1d8a4710de77a106fd76495cf64e1deb61e0;hpb=a756403301ff8fb78df4dc1e131e4cd50cd976e1;p=lyx.git diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 131f1d8a47..e4e10c088e 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -16,10 +16,12 @@ #include "Preamble.h" #include "tex2lyx.h" +#include "Encoding.h" #include "LayoutFile.h" #include "Layout.h" #include "Lexer.h" #include "TextClass.h" +#include "version.h" #include "support/convert.h" #include "support/FileName.h" @@ -37,39 +39,32 @@ using namespace lyx::support; namespace lyx { -// special columntypes -extern map special_columns; - 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. +// CJK languages are handled in text.cpp, polyglossia languages are listed +// further down. /** * 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", "australian", "austrian", "bahasa", "bahasai", -"bahasam", "basque", "belarusian", "brazil", "brazilian", "breton", "british", +"bahasam", "basque", "belarusian", "bosnian", "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", -"portuges", "portuguese", "romanian", "russian", "russianb", "samin", -"scottish", "serbian", "serbian-latin", "slovak", "slovene", "spanish", -"swedish", "thai", "turkish", "turkmen", "ukraineb", "ukrainian", -"uppersorbian", "UKenglish", "USenglish", "usorbian", "vietnam", "welsh", +"french", "frenchb", "frenchle", "frenchpro", "friulan", "galician", "german", "germanb", +"georgian", "greek", "hebrew", "hungarian", "icelandic", "indon", "indonesian", +"interlingua", "irish", "italian", "japanese", "kazakh", "kurmanji", "latin", +"latvian", "lithuanian", "lowersorbian", "lsorbian", "macedonian", "magyar", "malay", "meyalu", +"mongolian", "naustrian", "newzealand", "ngerman", "ngermanb", "norsk", "nswissgerman", +"nynorsk", "piedmontese", "polutonikogreek", "polish", "portuges", "portuguese", +"romanian", "romansh", "russian", "russianb", "samin", "scottish", "serbian", "serbian-latin", +"slovak", "slovene", "spanish", "swedish", "swissgerman", "thai", "turkish", "turkmen", +"ukraineb", "ukrainian", "uppersorbian", "UKenglish", "USenglish", "usorbian", +"vietnam", "welsh", 0}; /** @@ -78,45 +73,66 @@ const char * const known_languages[] = {"acadian", "afrikaans", "albanian", */ const char * const known_coded_languages[] = {"french", "afrikaans", "albanian", "american", "arabic_arabi", "arabic_arabtex", "australian", "austrian", "bahasa", "bahasa", -"bahasam", "basque", "belarusian", "brazilian", "brazilian", "breton", "british", +"bahasam", "basque", "belarusian", "bosnian", "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", "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", -"uppersorbian", "uppersorbian", "english", "english", "vietnamese", "welsh", +"french", "french", "french", "french", "friulan", "galician", "german", "german", +"georgian", "greek", "hebrew", "magyar", "icelandic", "bahasa", "bahasa", +"interlingua", "irish", "italian", "japanese", "kazakh", "kurmanji", "latin", +"latvian", "lithuanian", "lowersorbian", "lowersorbian", "macedonian", "magyar", "bahasam", "bahasam", +"mongolian", "naustrian", "newzealand", "ngerman", "ngerman", "norsk", "german-ch", +"nynorsk", "piedmontese", "polutonikogreek", "polish", "portuguese", "portuguese", +"romanian", "romansh", "russian", "russian", "samin", "scottish", "serbian", "serbian-latin", +"slovak", "slovene", "spanish", "swedish", "german-ch-old", "thai", "turkish", "turkmen", +"ukrainian", "ukrainian", "uppersorbian", "english", "english", "uppersorbian", +"vietnamese", "welsh", 0}; +/// languages with british quotes (.lyx names) +const char * const known_british_quotes_languages[] = {"british", "welsh", 0}; + +/// languages with cjk quotes (.lyx names) +const char * const known_cjk_quotes_languages[] = {"chinese-traditional", +"japanese", "japanese-cjk", 0}; + +/// languages with cjk-angle quotes (.lyx names) +const char * const known_cjkangle_quotes_languages[] = {"korean", 0}; + +/// languages with danish quotes (.lyx names) +const char * const known_danish_quotes_languages[] = {"danish", 0}; + /// languages with english quotes (.lyx names) 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}; +"esperanto", "farsi", "interlingua", "irish", "newzealand", "scottish", +"thai", "turkish", "vietnamese", 0}; /// languages with french quotes (.lyx names) -const char * const known_french_quotes_languages[] = {"albanian", -"arabic_arabi", "arabic_arabtex", "basque", "canadien", "catalan", "french", -"galician", "greek", "italian", "norsk", "nynorsk", "polutonikogreek", -"russian", "spanish", "spanish-mexico", "turkish", "turkmen", "ukrainian", -"vietnamese", 0}; +const char * const known_french_quotes_languages[] = {"ancientgreek", +"arabic_arabi", "arabic_arabtex", "asturian", "belarusian", "breton", +"canadien", "catalan", "french", "friulan", "galician", "italian", "occitan", +"piedmontese", "portuguese", "spanish", "spanish-mexico", 0}; /// languages with german quotes (.lyx names) const char * const known_german_quotes_languages[] = {"austrian", "bulgarian", -"czech", "german", "icelandic", "lithuanian", "lowersorbian", "naustrian", -"ngerman", "serbian", "serbian-latin", "slovak", "slovene", "uppersorbian", 0}; +"czech", "estonian", "georgian", "german", "icelandic", "latvian", "lithuanian", +"lowersorbian", "macedonian", "naustrian", "ngerman", "romansh", "slovak", "slovene", +"uppersorbian", 0}; /// languages with polish quotes (.lyx names) -const char * const known_polish_quotes_languages[] = {"afrikaans", "croatian", -"dutch", "estonian", "magyar", "polish", "romanian", 0}; +const char * const known_polish_quotes_languages[] = {"afrikaans", "bosnian", "croatian", +"dutch", "magyar", "polish", "romanian", "serbian", "serbian-latin", 0}; + +/// languages with russian quotes (.lyx names) +const char * const known_russian_quotes_languages[] = {"russian", "ukrainian", 0}; /// languages with swedish quotes (.lyx names) -const char * const known_swedish_quotes_languages[] = {"finnish", -"swedish", 0}; +const char * const known_swedish_quotes_languages[] = {"finnish", "swedish", 0}; + +/// languages with swiss quotes (.lyx names) +const char * const known_swiss_quotes_languages[] = {"albanian", +"armenian", "basque", "german-ch", "german-ch-old", +"norsk", "nynorsk", "turkmen", "ukrainian", "vietnamese", 0}; /// known language packages from the times before babel const char * const known_old_language_packages[] = {"french", "frenchle", @@ -125,15 +141,21 @@ const char * const known_old_language_packages[] = {"french", "frenchle", char const * const known_fontsizes[] = { "10pt", "11pt", "12pt", 0 }; const char * const known_roman_fonts[] = { "ae", "beraserif", "bookman", -"ccfonts", "chancery", "charter", "cmr", "fourier", "lmodern", "mathpazo", -"mathptmx", "newcent", "utopia", 0}; +"ccfonts", "chancery", "charter", "cmr", "cochineal", "crimson", "fourier", +"garamondx", "libertine", "libertineRoman", "libertine-type1", "lmodern", "mathdesign", "mathpazo", +"mathptmx", "MinionPro", "newcent", "NotoSerif-TLF", "PTSerif-TLF", "tgbonum", "tgchorus", +"tgpagella", "tgschola", "tgtermes", "utopia", "xcharter", 0 }; -const char * const known_sans_fonts[] = { "avant", "berasans", "cmbr", "cmss", -"helvet", "lmss", 0}; +const char * const known_sans_fonts[] = { "avant", "berasans", "biolinum", +"biolinum-type1", "cmbr", "cmss", "helvet", "iwona", "iwonac", "iwonal", "iwonalc", +"kurier", "kurierc", "kurierl", "kurierlc", "lmss", "NotoSans-TLF", "PTSans-TLF", +"tgadventor", "tgheros", "uop", 0 }; const char * const known_typewriter_fonts[] = { "beramono", "cmtl", "cmtt", -"courier", "lmtt", "luximono", "fourier", "lmodern", "mathpazo", "mathptmx", -"newcent", 0}; +"courier", "lmtt", "luximono", "fourier", "libertineMono", "libertineMono-type1", "lmodern", +"mathpazo", "mathptmx", "newcent", "NotoMono-TLF", "PTMono-TLF", "tgcursor", "txtt", 0 }; + +const char * const known_math_fonts[] = { "eulervm", "newtxmath", 0}; const char * const known_paper_sizes[] = { "a0paper", "b0paper", "c0paper", "a1paper", "b1paper", "c1paper", "a2paper", "b2paper", "c2paper", "a3paper", @@ -156,27 +178,37 @@ const char * const known_if_commands[] = {"if", "ifarydshln", "ifbraket", "ifcancel", "ifcolortbl", "ifeurosym", "ifmarginnote", "ifmmode", "ifpdf", "ifsidecap", "ifupgreek", 0}; -const char * const known_basic_colors[] = {"blue", "black", "cyan", "green", -"magenta", "red", "white", "yellow", 0}; +const char * const known_basic_colors[] = {"black", "blue", "brown", "cyan", + "darkgray", "gray", "green", "lightgray", "lime", "magenta", "orange", "olive", + "pink", "purple", "red", "teal", "violet", "white", "yellow", 0}; -const char * const known_basic_color_codes[] = {"#0000ff", "#000000", "#00ffff", "#00ff00", -"#ff00ff", "#ff0000", "#ffffff", "#ffff00", 0}; +const char * const known_basic_color_codes[] = {"#000000", "#0000ff", "#964B00", "#00ffff", + "#a9a9a9", "#808080", "#00ff00", "#d3d3d3", "#bfff00", "#ff00ff", "#ff7f00", "#808000", + "#ffc0cb", "#800080", "#ff0000", "#008080", "#8f00ff", "#ffffff", "#ffff00", 0}; /// conditional commands with three arguments like \@ifundefined{}{}{} const char * const known_if_3arg_commands[] = {"@ifundefined", "IfFileExists", 0}; +/*! + * Known file extensions for TeX files as used by \\includeonly + */ +char const * const known_tex_extensions[] = {"tex", 0}; + /// packages that work only in xetex +/// polyglossia is handled separately const char * const known_xetex_packages[] = {"arabxetex", "fixlatvian", -"fontbook", "fontwrap", "mathspec", "philokalia", "polyglossia", "unisugar", +"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", "booktabs", "calc", "color", "float", -"graphicx", "hhline", "ifthen", "longtable", "makeidx", "multirow", -"nomencl", "pdfpages", "rotating", "rotfloat", "splitidx", "setspace", -"subscript", "textcomp", "ulem", "url", "varioref", "verbatim", "wrapfig", 0}; +"amstext", "amsthm", "array", "babel", "booktabs", "calc", "CJK", "color", +"float", "fontspec", "framed", "graphicx", "hhline", "ifthen", "longtable", +"makeidx", "minted", "multirow", "nomencl", "pdfpages", "prettyref", "refstyle", +"rotating", "rotfloat", "splitidx", "setspace", "subscript", "tabularx","textcomp", "tipa", +"tipx", "tone", "ulem", "url", "varioref", "verbatim", "wrapfig", "xcolor", "xltabular", +"xunicode", 0}; // codes used to remove packages that are loaded automatically by LyX. // Syntax: package_beg_seppackage_mid_seppackage_end_sep @@ -249,7 +281,7 @@ vector split_options(string const & input) p.skip_spaces(true); if (p.next_token().asInput() == "{") option += '{' + p.getArg('{', '}') + '}'; - } else if (t.cat() != catSpace) + } else if (t.cat() != catSpace && t.cat() != catComment) option += t.asInput(); } @@ -284,6 +316,51 @@ string process_keyval_opt(vector & options, string name) } // anonymous namespace +/** + * known polyglossia language names (including variants) + * FIXME: support spelling=old for german variants (german vs. ngerman LyX names etc) + */ +const char * const Preamble::polyglossia_languages[] = { +"albanian", "american", "amharic", "ancient", "arabic", "armenian", "asturian", "australian", +"bahasai", "bahasam", "basque", "bengali", "brazil", "brazilian", "breton", "british", "bulgarian", +"catalan", "coptic", "croatian", "czech", "danish", "divehi", "dutch", +"english", "esperanto", "estonian", "farsi", "finnish", "french", "friulan", +"galician", "greek", "monotonic", "hebrew", "hindi", +"icelandic", "interlingua", "irish", "italian", "kannada", "khmer", +"lao", "latin", "latvian", "lithuanian", "lsorbian", "magyar", "malayalam", "marathi", +"austrian", "newzealand", "german", "norsk", "nynorsk", "occitan", +"piedmontese", "polish", "polytonic", "portuges", "romanian", "romansh", "russian", +"samin", "sanskrit", "scottish", "serbian", "slovak", "slovenian", "spanish", "swedish", "syriac", +"tamil", "telugu", "thai", "tibetan", "turkish", "turkmen", +"ukrainian", "urdu", "usorbian", "vietnamese", "welsh", 0}; +// not yet supported by LyX: "korean", "nko" + +/** + * 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", "american", "amharic", "ancientgreek", "arabic_arabi", "armenian", "asturian", "australian", +"bahasa", "bahasam", "basque", "bengali", "brazilian", "brazilian", "breton", "british", "bulgarian", +"catalan", "coptic", "croatian", "czech", "danish", "divehi", "dutch", +"english", "esperanto", "estonian", "farsi", "finnish", "french", "friulan", +"galician", "greek", "greek", "hebrew", "hindi", +"icelandic", "interlingua", "irish", "italian", "kannada", "khmer", +"lao", "latin", "latvian", "lithuanian", "lowersorbian", "magyar", "malayalam", "marathi", +"naustrian","newzealand", "ngerman", "norsk", "nynorsk", "occitan", +"piedmontese", "polish", "polutonikogreek", "portuges", "romanian", "romansh", "russian", +"samin", "sanskrit", "scottish", "serbian", "slovak", "slovene", "spanish", "swedish", "syriac", +"tamil", "telugu", "thai", "tibetan", "turkish", "turkmen", +"ukrainian", "urdu", "uppersorbian", "vietnamese", "welsh", 0}; +// not yet supported by LyX: "korean-polyglossia", "nko" + + +bool Preamble::usePolyglossia() const +{ + return h_use_non_tex_fonts && h_language_package == "default"; +} + + bool Preamble::indentParagraphs() const { return h_paragraph_separation == "indent"; @@ -348,12 +425,30 @@ Author const & Preamble::getAuthor(std::string const & name) const } +int Preamble::getSpecialTableColumnArguments(char c) const +{ + map::const_iterator it = special_columns_.find(c); + if (it == special_columns_.end()) + return -1; + return it->second; +} + + void Preamble::add_package(string const & name, vector & options) { // every package inherits the global options if (used_packages.find(name) == used_packages.end()) used_packages[name] = split_options(h_options); + // Insert options passed via PassOptionsToPackage + for (auto const & p : extra_package_options_) { + if (p.first == name) { + vector eo = getVectorFromString(p.second); + for (auto const & eoi : eo) + options.push_back(eoi); + } + + } vector & v = used_packages[name]; v.insert(v.end(), options.begin(), options.end()); if (name == "jurabib") { @@ -369,18 +464,19 @@ void Preamble::add_package(string const & name, vector & options) namespace { -// Given is a string like "scaled=0.9", return 0.9 * 100 -string const scale_as_percentage(string const & scale) +// Given is a string like "scaled=0.9" or "Scale=0.9", return 0.9 * 100 +bool scale_as_percentage(string const & scale, string & percentage) { string::size_type pos = scale.find('='); if (pos != string::npos) { string value = scale.substr(pos + 1); - if (isStrDbl(value)) - return convert(100 * convert(value)); + if (isStrDbl(value)) { + percentage = convert( + static_cast(100 * convert(value))); + return true; + } } - // If the input string didn't match our expectations. - // return the default value "100" - return "100"; + return false; } @@ -396,39 +492,60 @@ string remove_braces(string const & value) } // anonymous namespace -Preamble::Preamble() : one_language(true), title_layout_found(false) +Preamble::Preamble() : one_language(true), explicit_babel(false), + title_layout_found(false), index_number(0), h_font_cjk_set(false), + h_use_microtype("false") { //h_backgroundcolor; //h_boxbgcolor; h_biblio_style = "plain"; + h_bibtex_command = "default"; h_cite_engine = "basic"; - h_cite_engine_type = "numerical"; + h_cite_engine_type = "default"; + h_color = "#008000"; h_defskip = "medskip"; + h_dynamic_quotes = false; //h_float_placement; //h_fontcolor; h_fontencoding = "default"; - h_font_roman = "default"; - h_font_sans = "default"; - h_font_typewriter = "default"; + h_font_roman[0] = "default"; + h_font_roman[1] = "default"; + h_font_sans[0] = "default"; + h_font_sans[1] = "default"; + h_font_typewriter[0] = "default"; + h_font_typewriter[1] = "default"; + h_font_math[0] = "auto"; + h_font_math[1] = "auto"; h_font_default_family = "default"; - h_use_non_tex_fonts = "false"; + 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_font_sf_scale[0] = "100"; + h_font_sf_scale[1] = "100"; + h_font_tt_scale[0] = "100"; + h_font_tt_scale[1] = "100"; + //h_font_cjk + h_is_mathindent = "0"; + h_math_numbering_side = "default"; 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[0] = "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"; @@ -441,7 +558,7 @@ Preamble::Preamble() : one_language(true), title_layout_found(false) //h_pdf_author; //h_pdf_subject; //h_pdf_keywords; - h_pdf_bookmarks = "1"; + h_pdf_bookmarks = "0"; h_pdf_bookmarksnumbered = "0"; h_pdf_bookmarksopen = "0"; h_pdf_bookmarksopenlevel = "1"; @@ -449,28 +566,36 @@ Preamble::Preamble() : one_language(true), title_layout_found(false) h_pdf_pdfborder = "0"; h_pdf_colorlinks = "0"; h_pdf_backref = "section"; - h_pdf_pdfusetitle = "1"; + h_pdf_pdfusetitle = "0"; //h_pdf_pagemode; //h_pdf_quoted_options; - h_quotes_language = "english"; + h_quotes_style = "english"; h_secnumdepth = "3"; + h_shortcut[0] = "idx"; h_spacing = "single"; + h_save_transient_properties = "true"; h_suppress_date = "false"; h_textclass = "article"; h_tocdepth = "3"; h_tracking_changes = "false"; h_use_bibtopic = "false"; + h_use_dash_ligatures = "true"; h_use_indices = "false"; h_use_geometry = "false"; h_use_default_options = "false"; - h_use_hyperref = "0"; - h_use_refstyle = "0"; + h_use_hyperref = "false"; + h_use_microtype = "false"; + h_use_refstyle = false; + h_use_minted = false; h_use_packages["amsmath"] = "1"; h_use_packages["amssymb"] = "0"; + h_use_packages["cancel"] = "0"; h_use_packages["esint"] = "1"; h_use_packages["mhchem"] = "0"; h_use_packages["mathdots"] = "0"; h_use_packages["mathtools"] = "0"; + h_use_packages["stackrel"] = "0"; + h_use_packages["stmaryrd"] = "0"; h_use_packages["undertilde"] = "0"; } @@ -479,7 +604,7 @@ void Preamble::handle_hyperref(vector & options) { // FIXME swallow inputencoding changes that might surround the // hyperref setup if it was written by LyX - h_use_hyperref = "1"; + h_use_hyperref = "true"; // swallow "unicode=true", since LyX does always write that vector::iterator it = find(options.begin(), options.end(), "unicode=true"); @@ -590,44 +715,159 @@ void Preamble::handle_geometry(vector & options) void Preamble::handle_package(Parser &p, string const & name, - string const & opts, bool in_lyx_preamble) + string const & opts, bool in_lyx_preamble, + bool detectEncoding) { vector options = split_options(opts); add_package(name, options); - string scale; if (is_known(name, known_xetex_packages)) { xetex = true; - h_use_non_tex_fonts = "true"; + h_use_non_tex_fonts = true; + registerAutomaticallyLoadedPackage("fontspec"); if (h_inputencoding == "auto") - p.setEncoding("utf8"); + p.setEncoding("UTF-8"); } // roman fonts - if (is_known(name, known_roman_fonts)) { - h_font_roman = name; - p.skip_spaces(); - } + if (is_known(name, known_roman_fonts)) + h_font_roman[0] = name; if (name == "fourier") { - h_font_roman = "utopia"; + h_font_roman[0] = "utopia"; // when font uses real small capitals if (opts == "expert") h_font_sc = "true"; } + if (name == "garamondx") { + h_font_roman[0] = "garamondx"; + if (opts == "osfI") + h_font_osf = "true"; + } + + if (name == "libertine") { + h_font_roman[0] = "libertine"; + // this automatically invokes biolinum + h_font_sans[0] = "biolinum"; + // as well as libertineMono + h_font_typewriter[0] = "libertine-mono"; + if (opts == "osf") + h_font_osf = "true"; + else if (opts == "lining") + h_font_osf = "false"; + } + + if (name == "libertineRoman" || name == "libertine-type1") { + h_font_roman[0] = "libertine"; + // NOTE: contrary to libertine.sty, libertineRoman + // and libertine-type1 do not automatically invoke + // biolinum and libertineMono + if (opts == "lining") + h_font_osf = "false"; + else if (opts == "osf") + h_font_osf = "true"; + } + + if (name == "MinionPro") { + h_font_roman[0] = "minionpro"; + if (opts.find("lf") != string::npos) + h_font_osf = "false"; + else + h_font_osf = "true"; + if (opts.find("onlytext") != string::npos) + h_font_math[0] = "default"; + else + h_font_math[0] = "auto"; + } + + if (name == "mathdesign") { + if (opts.find("charter") != string::npos) + h_font_roman[0] = "md-charter"; + if (opts.find("garamond") != string::npos) + h_font_roman[0] = "md-garamond"; + if (opts.find("utopia") != string::npos) + h_font_roman[0] = "md-utopia"; + if (opts.find("expert") != string::npos) { + h_font_sc = "true"; + h_font_osf = "true"; + } + } + else if (name == "mathpazo") - h_font_roman = "palatino"; + h_font_roman[0] = "palatino"; else if (name == "mathptmx") - h_font_roman = "times"; + h_font_roman[0] = "times"; + if (name == "crimson") + h_font_roman[0] = "cochineal"; + + if (name == "cochineal") { + h_font_roman[0] = "cochineal"; + // cochineal can have several options, e.g. [proportional,osf] + string::size_type pos = opts.find("osf"); + if (pos != string::npos) + h_font_osf = "true"; + } + + if (name == "noto") { + // noto can have several options + if (opts.empty()) + h_font_roman[0] = "NotoSerif-TLF"; + string::size_type pos = opts.find("rm"); + if (pos != string::npos) + h_font_roman[0] = "NotoSerif-TLF"; + pos = opts.find("sf"); + if (pos != string::npos) + h_font_sans[0] = "NotoSans-TLF"; + pos = opts.find("nott"); + if (pos != string::npos) { + h_font_roman[0] = "NotoSerif-TLF"; + h_font_sans[0] = "NotoSans-TLF"; + } + // noto as typewriter is handled in handling of \ttdefault + // special cases are handled in handling of \rmdefault and \sfdefault + } + + if (name == "paratype") { + // in this case all fonts are ParaType + h_font_roman[0] = "PTSerif-TLF"; + h_font_sans[0] = "default"; + h_font_typewriter[0] = "default"; + } + + if (name == "PTSerif") + h_font_roman[0] = "PTSerif-TLF"; + + if (name == "XCharter") { + h_font_roman[0] = "xcharter"; + if (opts == "osf") + h_font_osf = "true"; + } + // sansserif fonts if (is_known(name, known_sans_fonts)) { - h_font_sans = name; - if (!opts.empty()) { - scale = opts; - h_font_sf_scale = scale_as_percentage(scale); + h_font_sans[0] = name; + if (options.size() >= 1) { + if (scale_as_percentage(opts, h_font_sf_scale[0])) + options.clear(); + } + } + + if (name == "biolinum" || name == "biolinum-type1") { + h_font_sans[0] = "biolinum"; + // biolinum can have several options, e.g. [osf,scaled=0.97] + string::size_type pos = opts.find("osf"); + if (pos != string::npos) + h_font_osf = "true"; + } + + if (name == "PTSans") { + h_font_sans[0] = "PTSans-TLF"; + if (options.size() >= 1) { + if (scale_as_percentage(opts, h_font_sf_scale[0])) + options.clear(); } } @@ -636,27 +876,64 @@ void Preamble::handle_package(Parser &p, string const & name, // fourier can be set as roman font _only_ // fourier as typewriter is handled in handling of \ttdefault if (name != "fourier") { - h_font_typewriter = name; - if (!opts.empty()) { - scale = opts; - h_font_tt_scale = scale_as_percentage(scale); + h_font_typewriter[0] = name; + if (options.size() >= 1) { + if (scale_as_percentage(opts, h_font_tt_scale[0])) + options.clear(); } } } + if (name == "libertineMono" || name == "libertineMono-type1") + h_font_typewriter[0] = "libertine-mono"; + + if (name == "PTMono") { + h_font_typewriter[0] = "PTMono-TLF"; + if (options.size() >= 1) { + if (scale_as_percentage(opts, h_font_tt_scale[0])) + options.clear(); + } + } + // font uses old-style figure if (name == "eco") h_font_osf = "true"; + // math fonts + if (is_known(name, known_math_fonts)) + h_font_math[0] = name; + + if (name == "newtxmath") { + if (opts.empty()) + h_font_math[0] = "newtxmath"; + else if (opts == "garamondx") + h_font_math[0] = "garamondx-ntxm"; + else if (opts == "libertine") + h_font_math[0] = "libertine-ntxm"; + else if (opts == "minion") + h_font_math[0] = "minion-ntxm"; + else if (opts == "cochineal") + h_font_math[0] = "cochineal-ntxm"; + } + + if (name == "iwona") + if (opts == "math") + h_font_math[0] = "iwona-math"; + + if (name == "kurier") + if (opts == "math") + h_font_math[0] = "kurier-math"; + // after the detection and handling of special cases, we can remove the // fonts, otherwise they would appear in the preamble, see bug #7856 if (is_known(name, known_roman_fonts) || is_known(name, known_sans_fonts) - || is_known(name, known_typewriter_fonts)) + || is_known(name, known_typewriter_fonts) || is_known(name, known_math_fonts)) ; - - else if (name == "amsmath" || name == "amssymb" || + //"On". See the enum Package in BufferParams.h if you thought that "2" should have been "42" + else if (name == "amsmath" || name == "amssymb" || name == "cancel" || name == "esint" || name == "mhchem" || name == "mathdots" || - name == "mathtools" || name == "undertilde") + name == "mathtools" || name == "stackrel" || + name == "stmaryrd" || name == "undertilde") h_use_packages[name] = "2"; else if (name == "babel") { @@ -674,26 +951,66 @@ void Preamble::handle_package(Parser &p, string const & name, // 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); + if (h_language == "japanese") { + // For Japanese, the encoding isn't indicated in the source + // file, and there's really not much we can do. We could + // 1) offer a list of possible encodings to choose from, or + // 2) determine the encoding of the file by inspecting it. + // For the time being, we leave the encoding alone so that + // we don't get iconv errors when making a wrong guess, and + // we will output a note at the top of the document + // explaining what to do. + Encoding const * const enc = encodings.fromIconvName( + p.getEncoding(), Encoding::japanese, false); + if (enc) + h_inputencoding = enc->name(); + 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 + } else { h_preamble << "\\usepackage{babel}\n"; + explicit_babel = true; + } + } + + 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("UTF-8"); + } + + else if (name == "CJK") { + // set the encoding to "auto" because it might be set to "default" by the babel handling + // and this would not be correct for CJK + if (h_inputencoding == "default") + h_inputencoding = "auto"; + registerAutomaticallyLoadedPackage("CJK"); + } + + else if (name == "CJKutf8") { + h_inputencoding = "utf8-cjk"; + p.setEncoding("UTF-8"); + registerAutomaticallyLoadedPackage("CJKutf8"); } else if (name == "fontenc") { h_fontencoding = getStringFromVector(options, ","); - /* We could do the following for better round trip support, - * but this makes the document less portable, so I skip it: - if (h_fontencoding == lyxrc.fontenc) - h_fontencoding = "global"; - */ options.clear(); } @@ -701,14 +1018,33 @@ void Preamble::handle_package(Parser &p, string const & name, // h_inputencoding is only set when there is not more than one // inputenc option because otherwise h_inputencoding must be // set to "auto" (the default encoding of the document language) - // Therefore check for the "," character. + // Therefore check that exactly one option is passed to inputenc. // 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()) - p.setEncoding(options.back()); - options.clear(); + if (!options.empty()) { + string const encoding = options.back(); + Encoding const * const enc = encodings.fromLaTeXName( + encoding, Encoding::inputenc, true); + if (!enc) { + if (!detectEncoding) + cerr << "Unknown encoding " << encoding + << ". Ignoring." << std::endl; + } else { + if (!enc->unsafe() && options.size() == 1 && one_language == true) + h_inputencoding = enc->name(); + p.setEncoding(enc->iconvName()); + } + 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)) { @@ -718,9 +1054,6 @@ void Preamble::handle_package(Parser &p, string const & name, h_language_package = "\\usepackage{" + name + "}"; } - else if (name == "prettyref") - ; // ignore this FIXME: Use the package separator mechanism instead - else if (name == "lyxskak") { // ignore this and its options const char * const o[] = {"ps", "mover", 0}; @@ -730,10 +1063,22 @@ void Preamble::handle_package(Parser &p, string const & name, else if (is_known(name, known_lyx_packages) && options.empty()) { if (name == "splitidx") h_use_indices = "true"; - if (!in_lyx_preamble) + else if (name == "minted") + h_use_minted = true; + else if (name == "refstyle") + h_use_refstyle = true; + else if (name == "prettyref") + h_use_refstyle = false; + if (!in_lyx_preamble) { h_preamble << package_beg_sep << name << package_mid_sep << "\\usepackage{" - << name << "}\n" << package_end_sep; + << name << '}'; + if (p.next_token().cat() == catNewline || + (p.next_token().cat() == catSpace && + p.next_next_token().cat() == catNewline)) + h_preamble << '\n'; + h_preamble << package_end_sep; + } } else if (name == "geometry") @@ -742,8 +1087,8 @@ void Preamble::handle_package(Parser &p, string const & name, else if (name == "subfig") ; // ignore this FIXME: Use the package separator mechanism instead - else if (is_known(name, known_languages)) - h_language = name; + else if (char const * const * where = is_known(name, known_languages)) + h_language = known_coded_languages[where - known_languages]; else if (name == "natbib") { h_biblio_style = "plainnat"; @@ -760,29 +1105,105 @@ void Preamble::handle_package(Parser &p, string const & name, options.erase(it); } } + if (!options.empty()) + h_biblio_options = join(options, ","); + } + + else if (name == "biblatex") { + h_biblio_style = "plainnat"; + h_cite_engine = "biblatex"; + h_cite_engine_type = "authoryear"; + string opt; + vector::iterator it = + find(options.begin(), options.end(), "natbib"); + if (it != options.end()) { + options.erase(it); + h_cite_engine = "biblatex-natbib"; + } else { + opt = process_keyval_opt(options, "natbib"); + if (opt == "true") + h_cite_engine = "biblatex-natbib"; + } + opt = process_keyval_opt(options, "style"); + if (!opt.empty()) { + h_biblatex_citestyle = opt; + h_biblatex_bibstyle = opt; + } else { + opt = process_keyval_opt(options, "citestyle"); + if (!opt.empty()) + h_biblatex_citestyle = opt; + opt = process_keyval_opt(options, "bibstyle"); + if (!opt.empty()) + h_biblatex_bibstyle = opt; + } + opt = process_keyval_opt(options, "refsection"); + if (!opt.empty()) { + if (opt == "none" || opt == "part" + || opt == "chapter" || opt == "section" + || opt == "subsection") + h_multibib = opt; + else + cerr << "Ignoring unkown refesection value '" + << opt << "'."; + } + if (!options.empty()) { + h_biblio_options = join(options, ","); + options.clear(); + } } else if (name == "jurabib") { h_biblio_style = "jurabib"; h_cite_engine = "jurabib"; h_cite_engine_type = "authoryear"; + if (!options.empty()) + h_biblio_options = join(options, ","); } + else if (name == "bibtopic") + h_use_bibtopic = "true"; + + else if (name == "chapterbib") + h_multibib = "child"; + else if (name == "hyperref") handle_hyperref(options); + else if (name == "algorithm2e") { + // Load "algorithm2e" module + addModule("algorithm2e"); + // Add the package options to the global document options + if (!options.empty()) { + if (h_options.empty()) + h_options = join(options, ","); + else + h_options += ',' + join(options, ","); + } + } + else if (name == "microtype") { + //we internally support only microtype without params + if (options.empty()) + h_use_microtype = "true"; + else + h_preamble << "\\usepackage[" << opts << "]{microtype}"; + } + else if (!in_lyx_preamble) { if (options.empty()) - h_preamble << "\\usepackage{" << name << "}\n"; + h_preamble << "\\usepackage{" << name << '}'; else { h_preamble << "\\usepackage[" << opts << "]{" - << name << "}\n"; + << name << '}'; options.clear(); } + if (p.next_token().cat() == catNewline || + (p.next_token().cat() == catSpace && + p.next_next_token().cat() == catNewline)) + h_preamble << '\n'; } // We need to do something with the options... - if (!options.empty()) + if (!options.empty() && !detectEncoding) cerr << "Ignoring options '" << join(options, ",") << "' of package " << name << '.' << endl; @@ -808,38 +1229,8 @@ void Preamble::handle_if(Parser & p, bool in_lyx_preamble) } -bool Preamble::writeLyXHeader(ostream & os, bool subdoc) +bool Preamble::writeLyXHeader(ostream & os, bool subdoc, string const & outfiledir) { - // 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 - // (quotes for "japanese" and "chinese-traditional" are missing because - // they wouldn't be useful: http://www.lyx.org/trac/ticket/6383) - // conversion list taken from - // http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage - // (quotes for kazakh and interlingua are unknown) - // danish - if (h_language == "danish") - h_quotes_language = "danish"; - // french - else if (is_known(h_language, known_french_quotes_languages)) - h_quotes_language = "french"; - // german - else if (is_known(h_language, known_german_quotes_languages)) - h_quotes_language = "german"; - // polish - else if (is_known(h_language, known_polish_quotes_languages)) - h_quotes_language = "polish"; - // swedish - else if (is_known(h_language, known_swedish_quotes_languages)) - h_quotes_language = "swedish"; - //english - 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") @@ -851,10 +1242,16 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc) } // output the LyX file settings - os << "#LyX file created by tex2lyx " << PACKAGE_VERSION << "\n" + // Important: Keep the version formatting in sync with LyX and + // lyx2lyx (bug 7951) + string const origin = roundtripMode() ? "roundtrip" : outfiledir; + os << "#LyX file created by tex2lyx " << lyx_version_major << '.' + << lyx_version_minor << '\n' << "\\lyxformat " << LYX_FORMAT << '\n' << "\\begin_document\n" << "\\begin_header\n" + << "\\save_transient_properties " << h_save_transient_properties << "\n" + << "\\origin " << origin << "\n" << "\\textclass " << h_textclass << "\n"; string const raw = subdoc ? empty_string() : h_preamble.str(); if (!raw.empty()) { @@ -891,34 +1288,56 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc) os << *it << '\n'; os << "\\end_modules\n"; } - os << "\\language " << h_language << "\n" + if (!h_includeonlys.empty()) { + os << "\\begin_includeonly\n"; + for (auto const & iofile : h_includeonlys) + os << iofile << '\n'; + os << "\\end_includeonly\n"; + } + os << "\\maintain_unincluded_children " << h_maintain_unincluded_children << "\n" + << "\\language " << h_language << "\n" << "\\language_package " << h_language_package << "\n" << "\\inputencoding " << h_inputencoding << "\n" << "\\fontencoding " << h_fontencoding << "\n" - << "\\font_roman " << h_font_roman << "\n" - << "\\font_sans " << h_font_sans << "\n" - << "\\font_typewriter " << h_font_typewriter << "\n" + << "\\font_roman \"" << h_font_roman[0] + << "\" \"" << h_font_roman[1] << "\"\n" + << "\\font_sans \"" << h_font_sans[0] << "\" \"" << h_font_sans[1] << "\"\n" + << "\\font_typewriter \"" << h_font_typewriter[0] + << "\" \"" << h_font_typewriter[1] << "\"\n" + << "\\font_math \"" << h_font_math[0] << "\" \"" << h_font_math[1] << "\"\n" << "\\font_default_family " << h_font_default_family << "\n" - << "\\use_non_tex_fonts " << h_use_non_tex_fonts << "\n" + << "\\use_non_tex_fonts " << (h_use_non_tex_fonts ? "true" : "false") << '\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"; + << "\\font_sf_scale " << h_font_sf_scale[0] + << ' ' << h_font_sf_scale[1] << '\n' + << "\\font_tt_scale " << h_font_tt_scale[0] + << ' ' << h_font_tt_scale[1] << '\n'; + if (!h_font_cjk.empty()) + os << "\\font_cjk " << h_font_cjk << '\n'; + os << "\\use_microtype " << h_use_microtype << '\n' + << "\\use_dash_ligatures " << h_use_dash_ligatures << '\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" << "\\spacing " << h_spacing << "\n" << "\\use_hyperref " << h_use_hyperref << '\n'; - if (h_use_hyperref == "1") { + if (h_use_hyperref == "true") { if (!h_pdf_title.empty()) - os << "\\pdf_title \"" << h_pdf_title << "\"\n"; + os << "\\pdf_title " << Lexer::quoteString(h_pdf_title) << '\n'; if (!h_pdf_author.empty()) - os << "\\pdf_author \"" << h_pdf_author << "\"\n"; + os << "\\pdf_author " << Lexer::quoteString(h_pdf_author) << '\n'; if (!h_pdf_subject.empty()) - os << "\\pdf_subject \"" << h_pdf_subject << "\"\n"; + os << "\\pdf_subject " << Lexer::quoteString(h_pdf_subject) << '\n'; if (!h_pdf_keywords.empty()) - os << "\\pdf_keywords \"" << h_pdf_keywords << "\"\n"; + os << "\\pdf_keywords " << Lexer::quoteString(h_pdf_keywords) << '\n'; os << "\\pdf_bookmarks " << h_pdf_bookmarks << "\n" "\\pdf_bookmarksnumbered " << h_pdf_bookmarksnumbered << "\n" "\\pdf_bookmarksopen " << h_pdf_bookmarksopen << "\n" @@ -931,7 +1350,7 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc) if (!h_pdf_pagemode.empty()) os << "\\pdf_pagemode " << h_pdf_pagemode << '\n'; if (!h_pdf_quoted_options.empty()) - os << "\\pdf_quoted_options \"" << h_pdf_quoted_options << "\"\n"; + os << "\\pdf_quoted_options " << Lexer::quoteString(h_pdf_quoted_options) << '\n'; } os << "\\papersize " << h_papersize << "\n" << "\\use_geometry " << h_use_geometry << '\n'; @@ -941,12 +1360,21 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc) 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" + << "\\use_bibtopic " << h_use_bibtopic << "\n"; + if (!h_biblio_options.empty()) + os << "\\biblio_options " << h_biblio_options << "\n"; + if (!h_biblatex_bibstyle.empty()) + os << "\\biblatex_bibstyle " << h_biblatex_bibstyle << "\n"; + if (!h_biblatex_citestyle.empty()) + os << "\\biblatex_citestyle " << h_biblatex_citestyle << "\n"; + if (!h_multibib.empty()) + os << "\\multibib " << h_multibib << "\n"; + os << "\\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'; + << "\\use_refstyle " << h_use_refstyle << '\n' + << "\\use_minted " << h_use_minted << '\n'; if (!h_fontcolor.empty()) os << "\\fontcolor " << h_fontcolor << '\n'; if (!h_notefontcolor.empty()) @@ -955,6 +1383,19 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc) os << "\\backgroundcolor " << h_backgroundcolor << '\n'; if (!h_boxbgcolor.empty()) os << "\\boxbgcolor " << h_boxbgcolor << '\n'; + if (index_number != 0) + for (int i = 0; i < index_number; i++) { + os << "\\index " << h_index[i] << '\n' + << "\\shortcut " << h_shortcut[i] << '\n' + << "\\color " << h_color << '\n' + << "\\end_index\n"; + } + else { + os << "\\index " << h_index[0] << '\n' + << "\\shortcut " << h_shortcut[0] << '\n' + << "\\color " << h_color << '\n' + << "\\end_index\n"; + } os << h_margins << "\\secnumdepth " << h_secnumdepth << "\n" << "\\tocdepth " << h_tocdepth << "\n" @@ -963,7 +1404,12 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc) os << "\\defskip " << h_defskip << "\n"; else os << "\\paragraph_indentation " << h_paragraph_indentation << "\n"; - os << "\\quotes_language " << h_quotes_language << "\n" + os << "\\is_math_indent " << h_is_mathindent << "\n"; + if (!h_mathindentation.empty()) + os << "\\math_indentation " << h_mathindentation << "\n"; + os << "\\math_numbering_side " << h_math_numbering_side << "\n"; + os << "\\quotes_style " << h_quotes_style << "\n" + << "\\dynamic_quotes " << h_dynamic_quotes << "\n" << "\\papercolumns " << h_papercolumns << "\n" << "\\papersides " << h_papersides << "\n" << "\\paperpagestyle " << h_paperpagestyle << "\n"; @@ -985,7 +1431,14 @@ void Preamble::parse(Parser & p, string const & forceclass, TeX2LyXDocClass & tc) { // initialize fixed types - special_columns['D'] = 3; + special_columns_['D'] = 3; + parse(p, forceclass, false, tc); +} + + +void Preamble::parse(Parser & p, string const & forceclass, + bool detectEncoding, TeX2LyXDocClass & tc) +{ bool is_full_document = false; bool is_lyx_file = false; bool in_lyx_preamble = false; @@ -1001,11 +1454,19 @@ void Preamble::parse(Parser & p, string const & forceclass, } p.reset(); + if (detectEncoding && !is_full_document) + return; + while (is_full_document && p.good()) { + if (detectEncoding && h_inputencoding != "auto" && + h_inputencoding != "default") + return; + Token const & t = p.get_token(); #ifdef FILEDEBUG - cerr << "t: " << t << "\n"; + if (!detectEncoding) + cerr << "t: " << t << '\n'; #endif // @@ -1021,14 +1482,18 @@ void Preamble::parse(Parser & p, string const & forceclass, t.cat() == catBegin || t.cat() == catEnd || t.cat() == catAlign || - t.cat() == catParameter)) + t.cat() == catParameter)) { h_preamble << t.cs(); + continue; + } - else if (!in_lyx_preamble && - (t.cat() == catSpace || t.cat() == catNewline)) + if (!in_lyx_preamble && + (t.cat() == catSpace || t.cat() == catNewline)) { h_preamble << t.asInput(); + continue; + } - else if (t.cat() == catComment) { + if (t.cat() == catComment) { static regex const islyxfile("%% LyX .* created this file"); static regex const usercommands("User specified LaTeX commands"); @@ -1040,7 +1505,8 @@ void Preamble::parse(Parser & p, string const & forceclass, if (comment.size() > magicXeLaTeX.size() && comment.substr(0, magicXeLaTeX.size()) == magicXeLaTeX && h_inputencoding == "auto") { - cerr << "XeLaTeX comment found, switching to UTF8\n"; + if (!detectEncoding) + cerr << "XeLaTeX comment found, switching to UTF8\n"; h_inputencoding = "utf8"; } smatch sub; @@ -1052,29 +1518,108 @@ void Preamble::parse(Parser & p, string const & forceclass, in_lyx_preamble = false; else if (!in_lyx_preamble) h_preamble << t.asInput(); + continue; } - else if (t.cs() == "pagestyle") + if (t.cs() == "PassOptionsToPackage") { + string const poptions = p.getArg('{', '}'); + string const package = p.verbatim_item(); + extra_package_options_.insert(make_pair(package, poptions)); + continue; + } + + if (t.cs() == "pagestyle") { h_paperpagestyle = p.verbatim_item(); + continue; + } + + 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); + continue; + } - else if (t.cs() == "date") { + 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(); + continue; + } + + if (t.cs() == "setmainfont") { + // we don't care about the option + p.hasOpt() ? p.getOpt() : string(); + h_font_roman[1] = p.getArg('{', '}'); + continue; + } + + 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_as_percentage(fontopts.substr(pos + 1), scale); + else + scale_as_percentage(fontopts.substr(pos, i - pos), scale); + } + } + if (t.cs() == "setsansfont") { + if (!scale.empty()) + h_font_sf_scale[1] = scale; + h_font_sans[1] = p.getArg('{', '}'); + } else { + if (!scale.empty()) + h_font_tt_scale[1] = scale; + h_font_typewriter[1] = p.getArg('{', '}'); + } + continue; + } + + if (t.cs() == "date") { string argument = p.getArg('{', '}'); if (argument.empty()) h_suppress_date = "true"; else h_preamble << t.asInput() << '{' << argument << '}'; + continue; } - else if (t.cs() == "color") { + 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 (space.empty() && is_known(argument, known_basic_colors)) { h_fontcolor = rgbcolor2code(argument); - preamble.registerAutomaticallyLoadedPackage("color"); + registerAutomaticallyLoadedPackage("color"); } else if (space.empty() && argument == "document_fontcolor") - preamble.registerAutomaticallyLoadedPackage("color"); + registerAutomaticallyLoadedPackage("color"); // check the case that LyX's document_fontcolor is defined // but not used for \color else { @@ -1086,15 +1631,16 @@ void Preamble::parse(Parser & p, string const & forceclass, // is parsed before this h_fontcolor = ""; } + continue; } - else if (t.cs() == "pagecolor") { + 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 = rgbcolor2code(argument); } else if (argument == "page_backgroundcolor") - preamble.registerAutomaticallyLoadedPackage("color"); + registerAutomaticallyLoadedPackage("color"); // check the case that LyX's page_backgroundcolor is defined // but not used for \pagecolor else { @@ -1103,25 +1649,106 @@ void Preamble::parse(Parser & p, string const & forceclass, // is parsed before this h_backgroundcolor = ""; } + continue; } - else if (t.cs() == "makeatletter") { + if (t.cs() == "makeatletter") { // LyX takes care of this - p.setCatCode('@', catLetter); + p.setCatcode('@', catLetter); + continue; } - else if (t.cs() == "makeatother") { + if (t.cs() == "makeatother") { // LyX takes care of this - p.setCatCode('@', catOther); + p.setCatcode('@', catOther); + continue; + } + + if (t.cs() == "makeindex") { + // LyX will re-add this if a print index command is found + p.skip_spaces(); + continue; + } + + if (t.cs() == "newindex") { + string const indexname = p.getArg('[', ']'); + string const shortcut = p.verbatim_item(); + if (!indexname.empty()) + h_index[index_number] = indexname; + else + h_index[index_number] = shortcut; + h_shortcut[index_number] = shortcut; + index_number += 1; + p.skip_spaces(); + continue; + } + + if (t.cs() == "addbibresource") { + biblatex_bibliographies.push_back(removeExtension(p.getArg('{', '}'))); + continue; + } + + if (t.cs() == "bibliography") { + vector bibs = getVectorFromString(p.getArg('{', '}')); + biblatex_bibliographies.insert(biblatex_bibliographies.end(), bibs.begin(), bibs.end()); + continue; + } + + if (t.cs() == "RS@ifundefined") { + string const name = p.verbatim_item(); + string const body1 = p.verbatim_item(); + string const body2 = p.verbatim_item(); + // only non-lyxspecific stuff + if (in_lyx_preamble && + (name == "subsecref" || name == "thmref" || name == "lemref")) + p.skip_spaces(); + else { + ostringstream ss; + ss << '\\' << t.cs(); + ss << '{' << name << '}' + << '{' << body1 << '}' + << '{' << body2 << '}'; + h_preamble << ss.str(); + } + continue; } - else if (t.cs() == "newcommand" || t.cs() == "newcommandx" - || t.cs() == "renewcommand" || t.cs() == "renewcommandx" - || t.cs() == "providecommand" || t.cs() == "providecommandx" - || t.cs() == "DeclareRobustCommand" - || t.cs() == "DeclareRobustCommandx" - || t.cs() == "ProvideTextCommandDefault" - || t.cs() == "DeclareMathAccent") { + if (t.cs() == "AtBeginDocument") { + string const name = p.verbatim_item(); + // only non-lyxspecific stuff + if (in_lyx_preamble && + (name == "\\providecommand\\partref[1]{\\ref{part:#1}}" + || name == "\\providecommand\\chapref[1]{\\ref{chap:#1}}" + || name == "\\providecommand\\secref[1]{\\ref{sec:#1}}" + || name == "\\providecommand\\subsecref[1]{\\ref{subsec:#1}}" + || name == "\\providecommand\\parref[1]{\\ref{par:#1}}" + || name == "\\providecommand\\figref[1]{\\ref{fig:#1}}" + || name == "\\providecommand\\tabref[1]{\\ref{tab:#1}}" + || name == "\\providecommand\\algref[1]{\\ref{alg:#1}}" + || name == "\\providecommand\\fnref[1]{\\ref{fn:#1}}" + || name == "\\providecommand\\enuref[1]{\\ref{enu:#1}}" + || name == "\\providecommand\\eqref[1]{\\ref{eq:#1}}" + || name == "\\providecommand\\lemref[1]{\\ref{lem:#1}}" + || name == "\\providecommand\\thmref[1]{\\ref{thm:#1}}" + || name == "\\providecommand\\corref[1]{\\ref{cor:#1}}" + || name == "\\providecommand\\propref[1]{\\ref{prop:#1}}")) + p.skip_spaces(); + else { + ostringstream ss; + ss << '\\' << t.cs(); + ss << '{' << name << '}'; + h_preamble << ss.str(); + } + continue; + } + + if (t.cs() == "newcommand" || t.cs() == "newcommandx" + || t.cs() == "renewcommand" || t.cs() == "renewcommandx" + || t.cs() == "providecommand" || t.cs() == "providecommandx" + || t.cs() == "DeclareRobustCommand" + || t.cs() == "DeclareRobustCommandx" + || t.cs() == "ProvideTextCommandDefault" + || t.cs() == "DeclareMathAccent") { bool star = false; if (p.next_token().character() == '*') { p.get_token(); @@ -1131,26 +1758,44 @@ void Preamble::parse(Parser & p, string const & forceclass, string const opt1 = p.getFullOpt(); string const opt2 = p.getFullOpt(); string const body = p.verbatim_item(); + // store the in_lyx_preamble setting + bool const was_in_lyx_preamble = in_lyx_preamble; // font settings if (name == "\\rmdefault") - if (is_known(body, known_roman_fonts)) - h_font_roman = body; + if (is_known(body, known_roman_fonts)) { + h_font_roman[0] = body; + p.skip_spaces(); + in_lyx_preamble = true; + } if (name == "\\sfdefault") - if (is_known(body, known_sans_fonts)) - h_font_sans = body; + if (is_known(body, known_sans_fonts)) { + h_font_sans[0] = body; + p.skip_spaces(); + in_lyx_preamble = true; + } if (name == "\\ttdefault") - if (is_known(body, known_typewriter_fonts)) - h_font_typewriter = body; + if (is_known(body, known_typewriter_fonts)) { + h_font_typewriter[0] = body; + p.skip_spaces(); + in_lyx_preamble = true; + } if (name == "\\familydefault") { string family = body; // remove leading "\" h_font_default_family = family.erase(0,1); + p.skip_spaces(); + in_lyx_preamble = true; } - // remove the lyxdot definition that is re-added by LyX + // remove LyX-specific definitions that are re-added by LyX // if necessary - if (name == "\\lyxdot") + // \lyxline is an ancient command that is converted by tex2lyx into + // a \rule therefore remove its preamble code + if (name == "\\lyxdot" || name == "\\lyxarrow" + || name == "\\lyxline" || name == "\\LyX") { + p.skip_spaces(); in_lyx_preamble = true; + } // Add the command to the known commands add_known_command(name, opt1, !opt2.empty(), from_utf8(body)); @@ -1170,9 +1815,12 @@ void Preamble::parse(Parser & p, string const & forceclass, << opts << "{" << body << "}"; */ } + // restore the in_lyx_preamble setting + in_lyx_preamble = was_in_lyx_preamble; + continue; } - else if (t.cs() == "documentclass") { + if (t.cs() == "documentclass") { vector::iterator it; vector opts = split_options(p.getArg('[', ']')); handle_opt(opts, known_fontsizes, h_paperfontsize); @@ -1187,6 +1835,24 @@ void Preamble::parse(Parser & p, string const & forceclass, handle_opt(opts, known_languages, h_language); delete_opt(opts, known_languages); + // math indentation + if ((it = find(opts.begin(), opts.end(), "fleqn")) + != opts.end()) { + h_is_mathindent = "1"; + opts.erase(it); + } + // formula numbering side + if ((it = find(opts.begin(), opts.end(), "leqno")) + != opts.end()) { + h_math_numbering_side = "left"; + opts.erase(it); + } + else if ((it = find(opts.begin(), opts.end(), "reqno")) + != opts.end()) { + h_math_numbering_side = "right"; + opts.erase(it); + } + // paper orientation if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) { h_paperorientation = "landscape"; @@ -1224,9 +1890,11 @@ void Preamble::parse(Parser & p, string const & forceclass, // FIXME This does not work for classes that have a // different name in LyX than in LaTeX h_textclass = p.getArg('{', '}'); + p.skip_spaces(); + continue; } - else if (t.cs() == "usepackage") { + if (t.cs() == "usepackage") { string const options = p.getArg('[', ']'); string const name = p.getArg('{', '}'); vector vecnames; @@ -1235,16 +1903,27 @@ void Preamble::parse(Parser & p, string const & forceclass, vector::const_iterator end = vecnames.end(); for (; it != end; ++it) handle_package(p, trimSpaceAndEol(*it), options, - in_lyx_preamble); + in_lyx_preamble, detectEncoding); + continue; } - else if (t.cs() == "inputencoding") { + if (t.cs() == "inputencoding") { string const encoding = p.getArg('{','}'); - h_inputencoding = encoding; - p.setEncoding(encoding); + Encoding const * const enc = encodings.fromLaTeXName( + encoding, Encoding::inputenc, true); + if (!enc) { + if (!detectEncoding) + cerr << "Unknown encoding " << encoding + << ". Ignoring." << std::endl; + } else { + if (!enc->unsafe()) + h_inputencoding = enc->name(); + p.setEncoding(enc->iconvName()); + } + continue; } - else if (t.cs() == "newenvironment") { + if (t.cs() == "newenvironment") { string const name = p.getArg('{', '}'); string const opt1 = p.getFullOpt(); string const opt2 = p.getFullOpt(); @@ -1257,10 +1936,33 @@ void Preamble::parse(Parser & p, string const & forceclass, } add_known_environment(name, opt1, !opt2.empty(), from_utf8(beg), from_utf8(end)); + continue; + } + if (t.cs() == "newtheorem") { + bool star = false; + if (p.next_token().character() == '*') { + p.get_token(); + star = true; + } + string const name = p.getArg('{', '}'); + string const opt1 = p.getFullOpt(); + string const opt2 = p.getFullOpt(); + string const body = p.verbatim_item(); + string const opt3 = p.getFullOpt(); + string const cmd = star ? "\\newtheorem*" : "\\newtheorem"; + + string const complete = cmd + "{" + name + '}' + + opt1 + opt2 + '{' + body + '}' + opt3; + + add_known_theorem(name, opt1, !opt2.empty(), from_utf8(complete)); + + if (!in_lyx_preamble) + h_preamble << complete; + continue; } - else if (t.cs() == "def") { + 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 @@ -1271,9 +1973,10 @@ void Preamble::parse(Parser & p, string const & forceclass, if (!in_lyx_preamble) h_preamble << "\\def\\" << name << '{' << p.verbatim_item() << "}"; + continue; } - else if (t.cs() == "newcolumntype") { + if (t.cs() == "newcolumntype") { string const name = p.getArg('{', '}'); trimSpaceAndEol(name); int nargs = 0; @@ -1282,14 +1985,15 @@ void Preamble::parse(Parser & p, string const & forceclass, istringstream is(string(opts, 1)); is >> nargs; } - special_columns[name[0]] = nargs; + special_columns_[name[0]] = nargs; h_preamble << "\\newcolumntype{" << name << "}"; if (nargs) h_preamble << "[" << nargs << "]"; h_preamble << "{" << p.verbatim_item() << "}"; + continue; } - else if (t.cs() == "setcounter") { + if (t.cs() == "setcounter") { string const name = p.getArg('{', '}'); string const content = p.getArg('{', '}'); if (name == "secnumdepth") @@ -1298,9 +2002,10 @@ void Preamble::parse(Parser & p, string const & forceclass, h_tocdepth = content; else h_preamble << "\\setcounter{" << name << "}{" << content << "}"; + continue; } - else if (t.cs() == "setlength") { + if (t.cs() == "setlength") { string const name = p.verbatim_item(); string const content = p.verbatim_item(); // the paragraphs are only not indented when \parindent is set to zero @@ -1317,33 +2022,58 @@ void Preamble::parse(Parser & p, string const & forceclass, else if (content == "\\bigskipamount") h_defskip = "bigskip"; else - h_defskip = content; + h_defskip = translate_len(content); + } else if (name == "\\mathindent") { + h_mathindentation = translate_len(content); } else h_preamble << "\\setlength{" << name << "}{" << content << "}"; + continue; } - else if (t.cs() == "onehalfspacing") + if (t.cs() == "onehalfspacing") { h_spacing = "onehalf"; + continue; + } - else if (t.cs() == "doublespacing") + if (t.cs() == "doublespacing") { h_spacing = "double"; + continue; + } - else if (t.cs() == "setstretch") + if (t.cs() == "setstretch") { h_spacing = "other " + p.verbatim_item(); + continue; + } + + 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; + continue; + } - else if (t.cs() == "begin") { + if (t.cs() == "begin") { string const name = p.getArg('{', '}'); if (name == "document") break; h_preamble << "\\begin{" << name << "}"; + continue; } - else if (t.cs() == "geometry") { + if (t.cs() == "geometry") { vector opts = split_options(p.getArg('{', '}')); handle_geometry(opts); + continue; } - else if (t.cs() == "definecolor") { + if (t.cs() == "definecolor") { string const color = p.getArg('{', '}'); string const space = p.getArg('{', '}'); string const value = p.getArg('{', '}'); @@ -1364,12 +2094,15 @@ void Preamble::parse(Parser & p, string const & forceclass, << "}{" << space << "}{" << value << '}'; } + continue; } - else if (t.cs() == "bibliographystyle") + if (t.cs() == "bibliographystyle") { h_biblio_style = p.verbatim_item(); + continue; + } - else if (t.cs() == "jurabibsetup") { + if (t.cs() == "jurabibsetup") { // FIXME p.getArg('{', '}') is most probably wrong (it // does not handle nested braces). // Use p.verbatim_item() instead. @@ -1381,9 +2114,10 @@ void Preamble::parse(Parser & p, string const & forceclass, h_preamble << "\\jurabibsetup{" << join(jurabibsetup, ",") << '}'; } + continue; } - else if (t.cs() == "hypersetup") { + if (t.cs() == "hypersetup") { vector hypersetup = split_options(p.verbatim_item()); // add hypersetup to the hyperref package options @@ -1392,9 +2126,38 @@ void Preamble::parse(Parser & p, string const & forceclass, h_preamble << "\\hypersetup{" << join(hypersetup, ",") << '}'; } + continue; + } + + if (t.cs() == "includeonly") { + vector includeonlys = getVectorFromString(p.getArg('{', '}')); + for (auto & iofile : includeonlys) { + string filename(normalize_filename(iofile)); + string const path = getMasterFilePath(true); + // We want to preserve relative/absolute filenames, + // therefore path is only used for testing + if (!makeAbsPath(filename, path).exists()) { + // The file extension is probably missing. + // Now try to find it out. + string const tex_name = + find_file(filename, path, + known_tex_extensions); + if (!tex_name.empty()) + filename = tex_name; + } + string outname; + if (makeAbsPath(filename, path).exists()) + fix_child_filename(filename); + else + cerr << "Warning: Could not find included file '" + << filename << "'." << endl; + outname = changeExtension(filename, "lyx"); + h_includeonlys.push_back(outname); + } + continue; } - else if (is_known(t.cs(), known_if_3arg_commands)) { + if (is_known(t.cs(), known_if_3arg_commands)) { // prevent misparsing of \usepackage if it is used // as an argument (see e.g. our own output of // \@ifundefined above) @@ -1431,18 +2194,22 @@ void Preamble::parse(Parser & p, string const & forceclass, << '{' << arg2 << '}' << '{' << arg3 << '}'; } + continue; } - else if (is_known(t.cs(), known_if_commands)) { + if (is_known(t.cs(), known_if_commands)) { // must not parse anything in conditional code, since // LyX would output the parsed contents unconditionally if (!in_lyx_preamble) h_preamble << t.asInput(); handle_if(p, in_lyx_preamble); + continue; } - else if (!t.cs().empty() && !in_lyx_preamble) + if (!t.cs().empty() && !in_lyx_preamble) { h_preamble << '\\' << t.cs(); + continue; + } } // remove the whitespace @@ -1451,10 +2218,8 @@ void Preamble::parse(Parser & p, string const & forceclass, // Force textclass if the user wanted it if (!forceclass.empty()) h_textclass = forceclass; - if (noweb_mode && !prefixIs(h_textclass, "literate-")) - h_textclass.insert(0, "literate-"); tc.setName(h_textclass); - if (!tc.load()) { + if (!LayoutFileList::get().haveClass(h_textclass) || !tc.load()) { cerr << "Error: Could not read layout file for textclass \"" << h_textclass << "\"." << endl; exit(EXIT_FAILURE); } @@ -1463,6 +2228,84 @@ void Preamble::parse(Parser & p, string const & forceclass, ss << tc.sides(); h_papersides = ss.str(); } + + // If the CJK package is used we cannot set the document language from + // the babel options. Instead, we guess which language is used most + // and set this one. + default_language = h_language; + if (is_full_document && + (auto_packages.find("CJK") != auto_packages.end() || + auto_packages.find("CJKutf8") != auto_packages.end())) { + p.pushPosition(); + h_language = guessLanguage(p, default_language); + p.popPosition(); + if (explicit_babel && h_language != default_language) { + // We set the document language to a CJK language, + // but babel is explicitly called in the user preamble + // without options. LyX will not add the default + // language to the document options if it is either + // english, or no text is set as default language. + // Therefore we need to add a language option explicitly. + // FIXME: It would be better to remove all babel calls + // from the user preamble, but this is difficult + // without re-introducing bug 7861. + if (h_options.empty()) + h_options = lyx2babel(default_language); + else + h_options += ',' + lyx2babel(default_language); + } + } + + // Finally, set the quote style. + // LyX knows the following quotes styles: + // british, cjk, cjkangle, danish, english, french, german, + // polish, russian, swedish and swiss + // conversion list taken from + // https://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage + // (quotes for kazakh are unknown) + // british + if (is_known(h_language, known_british_quotes_languages)) + h_quotes_style = "british"; + // cjk + else if (is_known(h_language, known_cjk_quotes_languages)) + h_quotes_style = "cjk"; + // cjkangle + else if (is_known(h_language, known_cjkangle_quotes_languages)) + h_quotes_style = "cjkangle"; + // danish + else if (is_known(h_language, known_danish_quotes_languages)) + h_quotes_style = "danish"; + // french + else if (is_known(h_language, known_french_quotes_languages)) + h_quotes_style = "french"; + // german + else if (is_known(h_language, known_german_quotes_languages)) + h_quotes_style = "german"; + // polish + else if (is_known(h_language, known_polish_quotes_languages)) + h_quotes_style = "polish"; + // russian + else if (is_known(h_language, known_russian_quotes_languages)) + h_quotes_style = "russian"; + // swedish + else if (is_known(h_language, known_swedish_quotes_languages)) + h_quotes_style = "swedish"; + // swiss + else if (is_known(h_language, known_swiss_quotes_languages)) + h_quotes_style = "swiss"; + // english + else if (is_known(h_language, known_english_quotes_languages)) + h_quotes_style = "english"; +} + + +string Preamble::parseEncoding(Parser & p, string const & forceclass) +{ + TeX2LyXDocClass dummy; + parse(p, forceclass, true, dummy); + if (h_inputencoding != "auto" && h_inputencoding != "default") + return h_inputencoding; + return ""; } @@ -1475,6 +2318,24 @@ string babel2lyx(string const & language) } +string lyx2babel(string const & language) +{ + char const * const * where = is_known(language, known_coded_languages); + if (where) + return known_languages[where - known_coded_languages]; + return language; +} + + +string Preamble::polyglossia2lyx(string const & language) +{ + 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);