]> git.lyx.org Git - lyx.git/blobdiff - src/tex2lyx/Preamble.cpp
tex2lyx/Preamble.cpp: remove a FIXME, the problem was only in trunk (bug #8211) and...
[lyx.git] / src / tex2lyx / Preamble.cpp
index afc2b19cd29bad6f5a86c2eb1bb2223a3ca69606..c8bd9cbff9ceb549f6f11f39a5aa0c55ffc7f427 100644 (file)
@@ -40,8 +40,6 @@ namespace lyx {
 // special columntypes
 extern map<char, int> special_columns;
 
-const char * const modules_placeholder = "\001modules\001";
-
 Preamble preamble;
 
 namespace {
@@ -59,12 +57,12 @@ namespace {
  * 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",
+"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", "kazakh", "latin", "latvian", "lithuanian", "lowersorbian",
 "lsorbian", "magyar", "malay", "meyalu", "mongolian", "naustrian", "newzealand",
 "ngerman", "ngermanb", "norsk", "nynorsk", "polutonikogreek", "polish",
@@ -79,14 +77,14 @@ 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",
+"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", "kazakh", "latin", "latvian", "lithuanian", "lowersorbian",
-"lowersorbian", "magyar", "bahasam", "bahasam", "mongolian", "naustrian", "english",
+"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",
@@ -94,10 +92,46 @@ const char * const known_coded_languages[] = {"french", "afrikaans", "albanian",
 "uppersorbian", "uppersorbian", "english", "english", "vietnamese", "welsh",
 0};
 
+/**
+ * known polyglossia language names (including variants)
+ */
+const char * const 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 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};
+
 /// 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 +179,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 +201,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", "booktabs", "calc", "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_sep<name>package_mid_sep<package loading code>package_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<string> & opts, char const * const * what, string & target)
@@ -288,9 +342,15 @@ vector<string> 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)
 {
-       return subst(lyxpreamble, modules_placeholder, modules);
+       used_modules.push_back(module);
 }
 
 
@@ -303,6 +363,28 @@ void Preamble::suppressDate(bool suppress)
 }
 
 
+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
+{
+       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;
+}
+
+
 void Preamble::add_package(string const & name, vector<string> & options)
 {
        // every package inherits the global options
@@ -351,11 +433,13 @@ 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_cite_engine             = "basic";
+       h_cite_engine_type        = "numerical";
        h_defskip                 = "medskip";
        //h_float_placement;
        //h_fontcolor;
@@ -364,15 +448,18 @@ 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_inputencoding           = "auto";
+       h_justification           = "true";
        h_language                = "english";
        h_language_package        = "none";
        //h_listings_params;
@@ -411,15 +498,18 @@ Preamble::Preamble() : one_language(true), ifundefined_color_set(false)
        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_packages["amsmath"]    = "1";
+       h_use_packages["amssymb"]    = "0";
+       h_use_packages["esint"]      = "1";
+       h_use_packages["mhchem"]     = "0";
+       h_use_packages["mathdots"]   = "0";
+       h_use_packages["mathtools"]  = "0";
+       h_use_packages["undertilde"] = "0";
 }
 
 
@@ -507,6 +597,36 @@ void Preamble::handle_hyperref(vector<string> & options)
 }
 
 
+void Preamble::handle_geometry(vector<string> & options)
+{
+       h_use_geometry = "true";
+       vector<string>::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)
 {
@@ -514,6 +634,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;
@@ -527,10 +655,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
@@ -565,20 +693,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";
@@ -589,7 +707,6 @@ 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
@@ -604,9 +721,21 @@ void Preamble::handle_package(Parser &p, string const & name,
                        // reasons for it.
                        h_preamble << "\\usepackage[" << opts << "]{babel}\n";
                        delete_opt(options, known_languages);
+                       // finally translate the babel name to a LyX name
+                       h_language = babel2lyx(h_language);
                }
                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 == "fontenc") {
@@ -624,8 +753,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())
@@ -636,73 +765,41 @@ void Preamble::handle_package(Parser &p, string const & name,
        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
-
-       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
+               ; // ignore this FIXME: Use the package separator mechanism instead
 
-       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<string>::iterator it =
                        find(options.begin(), options.end(), "authoryear");
                if (it != options.end())
@@ -710,24 +807,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();
                }
        }
@@ -759,11 +859,8 @@ void Preamble::handle_if(Parser & p, bool in_lyx_preamble)
 }
 
 
-void Preamble::writeLyXHeader(ostream & os)
+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
@@ -791,19 +888,58 @@ void Preamble::writeLyXHeader(ostream & os)
        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
-          << "\\language " << h_language << "\n"
+       os << "\\use_default_options " << h_use_default_options << "\n";
+       if (!used_modules.empty()) {
+               os << "\\begin_modules\n";
+               vector<string>::const_iterator const end = used_modules.end();
+               vector<string>::const_iterator it = used_modules.begin();
+               for (; it != end; ++it)
+                       os << *it << '\n';
+               os << "\\end_modules\n";
+       }
+       os << "\\language " << h_language << "\n"
           << "\\language_package " << h_language_package << "\n"
           << "\\inputencoding " << h_inputencoding << "\n"
           << "\\fontencoding " << h_fontencoding << "\n"
@@ -811,11 +947,13 @@ void Preamble::writeLyXHeader(ostream & os)
           << "\\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";
        if (!h_float_placement.empty())
                os << "\\float_placement " << h_float_placement << "\n";
        os << "\\paperfontsize " << h_paperfontsize << "\n"
@@ -845,16 +983,18 @@ void Preamble::writeLyXHeader(ostream & os)
                        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<string, string>::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';
@@ -883,10 +1023,10 @@ void Preamble::writeLyXHeader(ostream & os)
           << "\\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;
 }
 
 
@@ -933,7 +1073,7 @@ void Preamble::parse(Parser & p, string const & forceclass,
                     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();
 
@@ -946,7 +1086,7 @@ void Preamble::parse(Parser & p, string const & forceclass,
                        // 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";
@@ -966,6 +1106,55 @@ void Preamble::parse(Parser & p, string const & forceclass,
                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);
+                               if (pos_var != string::npos){
+                                       string variant;
+                                       if (i == string::npos)
+                                               variant = langopts.substr(pos_var + 8, langopts.length() - pos_var - 9);
+                                       else
+                                               variant = langopts.substr(pos_var + 8, i - pos_var - 8);
+                                       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") {
+                       // we don't care about the option
+                       p.hasOpt() ? p.getOpt() : string();
+                       h_font_sans = p.getArg('{', '}');
+               }
+
+               else if (t.cs() == "setmonofont") {
+                       // we don't care about the option
+                       p.hasOpt() ? p.getOpt() : string();
+                       h_font_typewriter = p.getArg('{', '}');
+               }
+
                else if (t.cs() == "date") {
                        string argument = p.getArg('{', '}');
                        if (argument.empty())
@@ -975,15 +1164,22 @@ void Preamble::parse(Parser & p, string const & forceclass,
                }
 
                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 = "";
@@ -993,12 +1189,13 @@ void Preamble::parse(Parser & p, string const & forceclass,
                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
@@ -1048,6 +1245,11 @@ void Preamble::parse(Parser & p, string const & forceclass,
                                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));
 
@@ -1111,7 +1313,7 @@ void Preamble::parse(Parser & p, string const & forceclass,
                                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);
@@ -1130,7 +1332,7 @@ void Preamble::parse(Parser & p, string const & forceclass,
                        vector<string>::const_iterator it  = vecnames.begin();
                        vector<string>::const_iterator end = vecnames.end();
                        for (; it != end; ++it)
-                               handle_package(p, trimSpaceAndEol(*it), options, 
+                               handle_package(p, trimSpaceAndEol(*it), options,
                                               in_lyx_preamble);
                }
 
@@ -1158,8 +1360,12 @@ void Preamble::parse(Parser & p, string const & forceclass,
 
                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() << "}";
@@ -1231,32 +1437,8 @@ void Preamble::parse(Parser & p, string const & forceclass,
                }
 
                else if (t.cs() == "geometry") {
-                       h_use_geometry = "true";
                        vector<string> opts = split_options(p.getArg('{', '}'));
-                       vector<string>::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") {
@@ -1282,6 +1464,9 @@ void Preamble::parse(Parser & p, string const & forceclass,
                        }
                }
 
+               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).
@@ -1315,18 +1500,27 @@ void Preamble::parse(Parser & p, string const & forceclass,
                        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) {
@@ -1379,12 +1573,25 @@ string babel2lyx(string const & language)
 }
 
 
-string color2code(string const & name)
+string 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);
 }
 
 // }])