]> git.lyx.org Git - lyx.git/blobdiff - src/BufferParams.cpp
Account for old versions of Pygments
[lyx.git] / src / BufferParams.cpp
index 85a8cbb6631a2dd9182256f808a111f12ce41c86..38ca643400698da1c4247edc177423ac02437896 100644 (file)
 #include "Buffer.h"
 #include "buffer_funcs.h"
 #include "Bullet.h"
+#include "CiteEnginesList.h"
 #include "Color.h"
 #include "ColorSet.h"
 #include "Converter.h"
 #include "Encoding.h"
-#include "HSpace.h"
 #include "IndicesList.h"
 #include "Language.h"
 #include "LaTeXFeatures.h"
 #include "LaTeXFonts.h"
+#include "Length.h"
 #include "ModuleList.h"
 #include "Font.h"
 #include "Lexer.h"
@@ -71,8 +72,9 @@ static char const * const string_paragraph_separation[] = {
 };
 
 
-static char const * const string_quotes_language[] = {
-       "english", "swedish", "german", "polish", "french", "danish", ""
+static char const * const string_quotes_style[] = {
+       "english", "swedish", "german", "polish", "swiss", "danish", "plain",
+       "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle", ""
 };
 
 
@@ -127,27 +129,35 @@ ParSepTranslator const & parseptranslator()
 }
 
 
-// Quotes language
-typedef Translator<string, InsetQuotes::QuoteLanguage> QuotesLangTranslator;
+// Quotes style
+typedef Translator<string, InsetQuotesParams::QuoteStyle> QuotesStyleTranslator;
 
 
-QuotesLangTranslator const init_quoteslangtranslator()
+QuotesStyleTranslator const init_quotesstyletranslator()
 {
-       QuotesLangTranslator translator
-               (string_quotes_language[0], InsetQuotes::EnglishQuotes);
-       translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQuotes);
-       translator.addPair(string_quotes_language[2], InsetQuotes::GermanQuotes);
-       translator.addPair(string_quotes_language[3], InsetQuotes::PolishQuotes);
-       translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQuotes);
-       translator.addPair(string_quotes_language[5], InsetQuotes::DanishQuotes);
+       QuotesStyleTranslator translator
+               (string_quotes_style[0], InsetQuotesParams::EnglishQuotes);
+       translator.addPair(string_quotes_style[1], InsetQuotesParams::SwedishQuotes);
+       translator.addPair(string_quotes_style[2], InsetQuotesParams::GermanQuotes);
+       translator.addPair(string_quotes_style[3], InsetQuotesParams::PolishQuotes);
+       translator.addPair(string_quotes_style[4], InsetQuotesParams::SwissQuotes);
+       translator.addPair(string_quotes_style[5], InsetQuotesParams::DanishQuotes);
+       translator.addPair(string_quotes_style[6], InsetQuotesParams::PlainQuotes);
+       translator.addPair(string_quotes_style[7], InsetQuotesParams::BritishQuotes);
+       translator.addPair(string_quotes_style[8], InsetQuotesParams::SwedishGQuotes);
+       translator.addPair(string_quotes_style[9], InsetQuotesParams::FrenchQuotes);
+       translator.addPair(string_quotes_style[10], InsetQuotesParams::FrenchINQuotes);
+       translator.addPair(string_quotes_style[11], InsetQuotesParams::RussianQuotes);
+       translator.addPair(string_quotes_style[12], InsetQuotesParams::CJKQuotes);
+       translator.addPair(string_quotes_style[13], InsetQuotesParams::CJKAngleQuotes);
        return translator;
 }
 
 
-QuotesLangTranslator const & quoteslangtranslator()
+QuotesStyleTranslator const & quotesstyletranslator()
 {
-       static QuotesLangTranslator const translator =
-               init_quoteslangtranslator();
+       static QuotesStyleTranslator const translator =
+               init_quotesstyletranslator();
        return translator;
 }
 
@@ -263,27 +273,6 @@ PackageTranslator const & packagetranslator()
 }
 
 
-// Cite engine
-typedef Translator<string, CiteEngineType> CiteEngineTypeTranslator;
-
-
-CiteEngineTypeTranslator const init_citeenginetypetranslator()
-{
-       CiteEngineTypeTranslator translator("authoryear", ENGINE_TYPE_AUTHORYEAR);
-       translator.addPair("numerical", ENGINE_TYPE_NUMERICAL);
-       translator.addPair("default", ENGINE_TYPE_DEFAULT);
-       return translator;
-}
-
-
-CiteEngineTypeTranslator const & citeenginetypetranslator()
-{
-       static CiteEngineTypeTranslator const translator =
-               init_citeenginetypetranslator();
-       return translator;
-}
-
-
 // Spacing
 typedef Translator<string, Spacing::Space> SpaceTranslator;
 
@@ -348,18 +337,24 @@ public:
        Bullet user_defined_bullets[4];
        IndicesList indiceslist;
        Spacing spacing;
+       Length parindent;
+       Length mathindent;
        /** This is the amount of space used for paragraph_separation "skip",
         * and for detached paragraphs in "indented" documents.
         */
-       HSpace indentation;
        VSpace defskip;
        PDFOptions pdfoptions;
        LayoutFileIndex baseClass_;
+       FormatList exportableFormatList;
+       FormatList viewableFormatList;
+       bool isViewCacheValid;
+       bool isExportCacheValid;
 };
 
 
 BufferParams::Impl::Impl()
-       : defskip(VSpace::MEDSKIP), baseClass_(string(""))
+       : defskip(VSpace::MEDSKIP), baseClass_(string("")),
+         isViewCacheValid(false), isExportCacheValid(false)
 {
        // set initial author
        // FIXME UNICODE
@@ -389,7 +384,10 @@ BufferParams::BufferParams()
        cite_engine_type_ = ENGINE_TYPE_DEFAULT;
        makeDocumentClass();
        paragraph_separation = ParagraphIndentSeparation;
-       quotes_language = InsetQuotes::EnglishQuotes;
+       is_math_indent = false;
+       math_numbering_side = DEFAULT;
+       quotes_style = InsetQuotesParams::EnglishQuotes;
+       dynamic_quotes = false;
        fontsize = "default";
 
        /*  PaperLayout */
@@ -398,6 +396,7 @@ BufferParams::BufferParams()
        use_geometry = false;
        biblio_style = "plain";
        use_bibtopic = false;
+       multibib = string();
        use_indices = false;
        save_transient_properties = true;
        track_changes = false;
@@ -419,6 +418,7 @@ BufferParams::BufferParams()
        fonts_default_family = "default";
        useNonTeXFonts = false;
        use_microtype = false;
+       use_dash_ligatures = true;
        fonts_expert_sc = false;
        fonts_old_figures = false;
        fonts_sans_scale[0] = 100;
@@ -461,6 +461,7 @@ BufferParams::BufferParams()
 
        output_sync = false;
        use_refstyle = true;
+       use_minted = false;
 
        // map current author
        author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
@@ -527,6 +528,14 @@ map<string, string> const & BufferParams::auto_packages()
 }
 
 
+bool BufferParams::useBibtopic() const
+{
+       if (useBiblatex())
+               return false;
+       return (use_bibtopic || (!multibib.empty() && multibib != "child"));
+}
+
+
 AuthorList & BufferParams::authors()
 {
        return pimpl_->authorlist;
@@ -621,15 +630,27 @@ PDFOptions const & BufferParams::pdfoptions() const
 }
 
 
-HSpace const & BufferParams::getIndentation() const
+Length const & BufferParams::getMathIndent() const
 {
-       return pimpl_->indentation;
+       return pimpl_->mathindent;
 }
 
 
-void BufferParams::setIndentation(HSpace const & indent)
+void BufferParams::setMathIndent(Length const & indent)
 {
-       pimpl_->indentation = indent;
+       pimpl_->mathindent = indent;
+}
+
+
+Length const & BufferParams::getParIndent() const
+{
+       return pimpl_->parindent;
+}
+
+
+void BufferParams::setParIndent(Length const & indent)
+{
+       pimpl_->parindent = indent;
 }
 
 
@@ -647,6 +668,19 @@ void BufferParams::setDefSkip(VSpace const & vs)
 }
 
 
+BufferParams::MathNumber BufferParams::getMathNumber() const
+{
+       if (math_numbering_side != DEFAULT)
+               return math_numbering_side;
+       // FIXME: do not hardcode language here
+       else if (language->lang() == "arabic_arabi"
+                || documentClass().provides("leqno"))
+               return LEFT;
+       else
+               return RIGHT;
+}
+
+
 string BufferParams::readToken(Lexer & lex, string const & token,
        FileName const & filepath)
 {
@@ -808,14 +842,19 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                lex >> fonts_cjk;
        } else if (token == "\\use_microtype") {
                lex >> use_microtype;
+       } else if (token == "\\use_dash_ligatures") {
+               lex >> use_dash_ligatures;
        } else if (token == "\\paragraph_separation") {
                string parsep;
                lex >> parsep;
                paragraph_separation = parseptranslator().find(parsep);
        } else if (token == "\\paragraph_indentation") {
                lex.next();
-               string indentation = lex.getString();
-               pimpl_->indentation = HSpace(indentation);
+               string parindent = lex.getString();
+               if (parindent == "default")
+                       pimpl_->parindent = Length();
+               else
+                       pimpl_->parindent = Length(parindent);
        } else if (token == "\\defskip") {
                lex.next();
                string const defskip = lex.getString();
@@ -823,10 +862,30 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
                        // that is invalid
                        pimpl_->defskip = VSpace(VSpace::MEDSKIP);
-       } else if (token == "\\quotes_language") {
-               string quotes_lang;
-               lex >> quotes_lang;
-               quotes_language = quoteslangtranslator().find(quotes_lang);
+       } else if (token == "\\is_math_indent") {
+               lex >> is_math_indent;
+       } else if (token == "\\math_indentation") {
+               lex.next();
+               string mathindent = lex.getString();
+               if (mathindent == "default")
+                       pimpl_->mathindent = Length();
+               else
+                       pimpl_->mathindent = Length(mathindent);
+       } else if (token == "\\math_numbering_side") {
+               string tmp;
+               lex >> tmp;
+               if (tmp == "left")
+                       math_numbering_side = LEFT;
+               else if (tmp == "right")
+                       math_numbering_side = RIGHT;
+               else
+                       math_numbering_side = DEFAULT;
+       } else if (token == "\\quotes_style") {
+               string qstyle;
+               lex >> qstyle;
+               quotes_style = quotesstyletranslator().find(qstyle);
+       } else if (token == "\\dynamic_quotes") {
+               lex >> dynamic_quotes;
        } else if (token == "\\papersize") {
                string ppsize;
                lex >> ppsize;
@@ -846,12 +905,23 @@ string BufferParams::readToken(Lexer & lex, string const & token,
        } else if (token == "\\cite_engine_type") {
                string engine_type;
                lex >> engine_type;
-               cite_engine_type_ = citeenginetypetranslator().find(engine_type);
+               cite_engine_type_ = theCiteEnginesList.getType(engine_type);
        } else if (token == "\\biblio_style") {
                lex.eatLine();
                biblio_style = lex.getString();
+       } else if (token == "\\biblio_options") {
+               lex.eatLine();
+               biblio_opts = trim(lex.getString());
+       } else if (token == "\\biblatex_bibstyle") {
+               lex.eatLine();
+               biblatex_bibstyle = trim(lex.getString());
+       } else if (token == "\\biblatex_citestyle") {
+               lex.eatLine();
+               biblatex_citestyle = trim(lex.getString());
        } else if (token == "\\use_bibtopic") {
                lex >> use_bibtopic;
+       } else if (token == "\\multibib") {
+               lex >> multibib;
        } else if (token == "\\use_indices") {
                lex >> use_indices;
        } else if (token == "\\tracking_changes") {
@@ -1030,6 +1100,8 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                lex >> output_sync_macro;
        } else if (token == "\\use_refstyle") {
                lex >> use_refstyle;
+       } else if (token == "\\use_minted") {
+               lex >> use_minted;
        } else {
                lyxerr << "BufferParams::readToken(): Unknown token: " <<
                        token << endl;
@@ -1179,6 +1251,7 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const
                os << "\\font_cjk " << fonts_cjk << '\n';
        }
        os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
+       os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
        os << "\\graphics " << graphics_driver << '\n';
        os << "\\default_output_format " << default_output_format << '\n';
        os << "\\output_sync " << output_sync << '\n';
@@ -1217,14 +1290,26 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const
                os << "basic";
        }
 
-       os << "\n\\cite_engine_type " << citeenginetypetranslator().find(cite_engine_type_)
-          << "\n\\biblio_style " << biblio_style
-          << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
+       os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
+
+       if (!biblio_style.empty())
+               os << "\n\\biblio_style " << biblio_style;
+       if (!biblio_opts.empty())
+               os << "\n\\biblio_options " << biblio_opts;
+       if (!biblatex_bibstyle.empty())
+               os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
+       if (!biblatex_citestyle.empty())
+               os << "\n\\biblatex_citestyle " << biblatex_citestyle;
+       if (!multibib.empty())
+               os << "\n\\multibib " << multibib;
+
+       os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
           << "\n\\use_indices " << convert<string>(use_indices)
           << "\n\\paperorientation " << string_orientation[orientation]
           << "\n\\suppress_date " << convert<string>(suppress_date)
           << "\n\\justification " << convert<string>(justification)
           << "\n\\use_refstyle " << use_refstyle
+          << "\n\\use_minted " << use_minted
           << '\n';
        if (isbackgroundcolor == true)
                os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
@@ -1291,11 +1376,28 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const
           << "\n\\paragraph_separation "
           << string_paragraph_separation[paragraph_separation];
        if (!paragraph_separation)
-               os << "\n\\paragraph_indentation " << getIndentation().asLyXCommand();
+               os << "\n\\paragraph_indentation "
+                  << (getParIndent().empty() ? "default" : getParIndent().asString());
        else
                os << "\n\\defskip " << getDefSkip().asLyXCommand();
-       os << "\n\\quotes_language "
-          << string_quotes_language[quotes_language]
+       os << "\n\\is_math_indent " << is_math_indent;
+       if (is_math_indent)
+               os << "\n\\math_indentation "
+                  << (getMathIndent().empty() ? "default" : getMathIndent().asString());
+       os << "\n\\math_numbering_side ";
+       switch(math_numbering_side) {
+       case LEFT:
+               os << "left";
+               break;
+       case RIGHT:
+               os << "right";
+               break;
+       case DEFAULT:
+               os << "default";
+       }
+       os << "\n\\quotes_style "
+          << string_quotes_style[quotes_style]
+          << "\n\\dynamic_quotes " << dynamic_quotes
           << "\n\\papercolumns " << columns
           << "\n\\papersides " << sides
           << "\n\\paperpagestyle " << pagestyle << '\n';
@@ -1447,7 +1549,7 @@ void BufferParams::validate(LaTeXFeatures & features) const
 
        // some languages are only available via polyglossia
        if (features.hasPolyglossiaExclusiveLanguages())
-          features.require("polyglossia");
+               features.require("polyglossia");
 
        if (useNonTeXFonts && fontsMath() != "auto")
                features.require("unicode-math");
@@ -1574,6 +1676,21 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
            && orientation == ORIENTATION_LANDSCAPE)
                clsoptions << "landscape,";
 
+       if (is_math_indent)
+               clsoptions << "fleqn,";
+
+       switch(math_numbering_side) {
+       case LEFT:
+               clsoptions << "leqno,";
+               break;
+       case RIGHT:
+               clsoptions << "reqno,";
+               features.require("amsmath");
+               break;
+       case DEFAULT:
+               break;
+       }
+
        // language should be a parameter to \documentclass
        if (language->babel() == "hebrew"
            && default_language->babel() != "hebrew")
@@ -1617,7 +1734,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
 
        // if we use fontspec or newtxmath, we have to load the AMS packages here
        string const ams = features.loadAMSPackages();
-       bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1");
+       bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
        bool const use_newtxmath =
                theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
                        ot1, false, false) == "newtxmath";
@@ -1644,7 +1761,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        // set font encoding
        // XeTeX and LuaTeX (with OS fonts) do not need fontenc
        if (!useNonTeXFonts && !features.isProvided("fontenc")
-           && font_encoding() != "default") {
+           && main_font_encoding() != "default") {
                // get main font encodings
                vector<string> fontencs = font_encodings();
                // get font encodings of secondary languages
@@ -1891,9 +2008,19 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        } else {
                // when separation by indentation
                // only output something when a width is given
-               if (getIndentation().asLyXCommand() != "default") {
+               if (!getParIndent().empty()) {
                        os << "\\setlength{\\parindent}{"
-                          << from_utf8(getIndentation().asLatexCommand())
+                          << from_utf8(getParIndent().asLatexString())
+                          << "}\n";
+               }
+       }
+
+       if (is_math_indent) {
+               // when formula indentation
+               // only output something when it is not the default
+               if (!getMathIndent().empty()) {
+                       os << "\\setlength{\\mathindent}{"
+                          << from_utf8(getMathIndent().asString())
                           << "}\n";
                }
        }
@@ -1945,20 +2072,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                IndicesList::const_iterator iit = indiceslist().begin();
                IndicesList::const_iterator iend = indiceslist().end();
                for (; iit != iend; ++iit) {
-                       pair<docstring, docstring> indexname_latex =
-                               features.runparams().encoding->latexString(iit->index(),
-                                                                          features.runparams().dryrun);
-                       if (!indexname_latex.second.empty()) {
-                               // issue a warning about omitted characters
-                               // FIXME: should be passed to the error dialog
-                               frontend::Alert::warning(_("Uncodable characters"),
-                                       bformat(_("The following characters that are used in an index name are not\n"
-                                                 "representable in the current encoding and therefore have been omitted:\n%1$s."),
-                                               indexname_latex.second));
-                       }
-                       os << "\\newindex[";
-                       os << indexname_latex.first;
-                       os << "]{";
+                       os << "\\newindex{";
                        os << escape(iit->shortcut());
                        os << "}\n";
                }
@@ -2148,10 +2262,19 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        }
        if (features.isRequired("bicaption"))
                os << "\\usepackage{bicaption}\n";
-       if (!listings_params.empty() || features.mustProvide("listings"))
-               os << "\\usepackage{listings}\n";
+       if (!listings_params.empty()
+           || features.mustProvide("listings")
+           || features.mustProvide("minted")) {
+               if (features.mustProvide("listings"))
+                       os << "\\usepackage{listings}\n";
+               else
+                       os << "\\usepackage{minted}\n";
+       }
        if (!listings_params.empty()) {
-               os << "\\lstset{";
+               if (features.mustProvide("listings"))
+                       os << "\\lstset{";
+               else
+                       os << "\\setminted{";
                // do not test validity because listings_params is
                // supposed to be valid
                string par =
@@ -2160,14 +2283,21 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                os << "}\n";
        }
 
-       // xunicode needs to be loaded at least after amsmath, amssymb,
+       // xunicode only needs to be loaded if tipa is used
+       // (the rest is obsoleted by the new TU encoding).
+       // It needs to be loaded at least after amsmath, amssymb,
        // esint and the other packages that provide special glyphs
-       // The package only supports XeTeX currently.
-       if (features.runparams().flavor == OutputParams::XETEX
-           && useNonTeXFonts)
+       if (features.mustProvide("tipa") && useNonTeXFonts) {
+               // The package officially only supports XeTeX, but also works
+               // with LuaTeX. Thus we work around its XeTeX test.
+               if (features.runparams().flavor != OutputParams::XETEX) {
+                       os << "% Pretend to xunicode that we are XeTeX\n"
+                          << "\\def\\XeTeXpicfile{}\n";
+               }
                os << "\\usepackage{xunicode}\n";
+       }
 
-       // Polyglossia must be loaded last
+       // Polyglossia must be loaded last ...
        if (use_polyglossia) {
                // call the package
                os << "\\usepackage{polyglossia}\n";
@@ -2177,17 +2307,60 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                        os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
                os << "{" << from_ascii(language->polyglossia()) << "}\n";
                // now setup the other languages
-               std::map<std::string, std::string> const polylangs =
+               set<string> const polylangs =
                        features.getPolyglossiaLanguages();
-               for (std::map<std::string, std::string>::const_iterator mit = polylangs.begin();
+               for (set<string>::const_iterator mit = polylangs.begin();
                     mit != polylangs.end() ; ++mit) {
+                       // We do not output the options here; they are output in
+                       // the language switch commands. This is safer if multiple
+                       // varieties are used.
+                       if (*mit == language->polyglossia())
+                               continue;
                        os << "\\setotherlanguage";
-                       if (!mit->second.empty())
-                               os << "[" << from_ascii(mit->second) << "]";
-                       os << "{" << from_ascii(mit->first) << "}\n";
+                       os << "{" << from_ascii(*mit) << "}\n";
                }
        }
 
+       // ... but before biblatex (see #7065)
+       if (features.mustProvide("biblatex")) {
+               string delim = "";
+               string opts;
+               os << "\\usepackage";
+               if (!biblatex_bibstyle.empty()
+                   && (biblatex_bibstyle == biblatex_citestyle)) {
+                       opts = "style=" + biblatex_bibstyle;
+                       delim = ",";
+               } else {
+                       if (!biblatex_bibstyle.empty()) {
+                               opts = "bibstyle=" + biblatex_bibstyle;
+                               delim = ",";
+                       }
+                       if (!biblatex_citestyle.empty()) {
+                               opts += delim + "citestyle=" + biblatex_citestyle;
+                               delim = ",";
+                       }
+               }
+               if (!multibib.empty() && multibib != "child") {
+                       opts += delim + "refsection=" + multibib;
+                       delim = ",";
+               }
+               if (bibtexCommand() == "bibtex8"
+                   || prefixIs(bibtexCommand(), "bibtex8 ")) {
+                       opts += delim + "backend=bibtex8";
+                       delim = ",";
+               } else if (bibtexCommand() == "bibtex"
+                          || prefixIs(bibtexCommand(), "bibtex ")) {
+                       opts += delim + "backend=bibtex";
+                       delim = ",";
+               }
+               if (!biblio_opts.empty())
+                       opts += delim + biblio_opts;
+               if (!opts.empty())
+                       os << "[" << opts << "]";
+               os << "{biblatex}\n";
+       }
+
+
        // Load custom language package here
        if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
                if (lang_package == "default")
@@ -2198,7 +2371,8 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        }
 
        docstring const i18npreamble =
-               features.getTClassI18nPreamble(use_babel, use_polyglossia);
+               features.getTClassI18nPreamble(use_babel, use_polyglossia,
+                                              use_minted);
        if (!i18npreamble.empty())
                os << i18npreamble + '\n';
 
@@ -2251,6 +2425,7 @@ void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
 {
        // evil, but this function is evil
        doc_class_ = const_pointer_cast<DocumentClass>(tc);
+       invalidateConverterCache();
 }
 
 
@@ -2309,7 +2484,9 @@ void BufferParams::makeDocumentClass(bool const clone)
        if (!baseClass())
                return;
 
+       invalidateConverterCache();
        LayoutModuleList mods;
+       LayoutModuleList ces;
        LayoutModuleList::iterator it = layout_modules_.begin();
        LayoutModuleList::iterator en = layout_modules_.end();
        for (; it != en; ++it)
@@ -2318,9 +2495,9 @@ void BufferParams::makeDocumentClass(bool const clone)
        it = cite_engine_.begin();
        en = cite_engine_.end();
        for (; it != en; ++it)
-               mods.push_back(*it);
+               ces.push_back(*it);
 
-       doc_class_ = getDocumentClass(*baseClass(), mods, clone);
+       doc_class_ = getDocumentClass(*baseClass(), mods, ces, clone);
 
        TextClass::ReturnValues success = TextClass::OK;
        if (!forced_local_layout_.empty())
@@ -2384,49 +2561,46 @@ string BufferParams::bufferFormat() const
 }
 
 
-bool BufferParams::isExportable(string const & format) const
+bool BufferParams::isExportable(string const & format, bool need_viewable) const
 {
-       vector<string> backs = backends();
-       for (vector<string>::const_iterator it = backs.begin();
-            it != backs.end(); ++it)
-               if (theConverters().isReachable(*it, format))
+       FormatList const & formats = exportableFormats(need_viewable);
+       FormatList::const_iterator fit = formats.begin();
+       FormatList::const_iterator end = formats.end();
+       for (; fit != end ; ++fit) {
+               if ((*fit)->name() == format)
                        return true;
+       }
        return false;
 }
 
 
-vector<Format const *> BufferParams::exportableFormats(bool only_viewable) const
+FormatList const & BufferParams::exportableFormats(bool only_viewable) const
 {
+       FormatList & cached = only_viewable ?
+                       pimpl_->viewableFormatList : pimpl_->exportableFormatList;
+       bool & valid = only_viewable ? 
+                       pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
+       if (valid)
+               return cached;
+
        vector<string> const backs = backends();
        set<string> excludes;
        if (useNonTeXFonts) {
                excludes.insert("latex");
                excludes.insert("pdflatex");
        }
-       vector<Format const *> result =
+       FormatList result =
                theConverters().getReachable(backs[0], only_viewable, true, excludes);
        for (vector<string>::const_iterator it = backs.begin() + 1;
             it != backs.end(); ++it) {
-               vector<Format const *>  r =
-                       theConverters().getReachable(*it, only_viewable, false, excludes);
+               FormatList r = theConverters().getReachable(*it, only_viewable, 
+                               false, excludes);
                result.insert(result.end(), r.begin(), r.end());
        }
-       return result;
-}
-
-
-bool BufferParams::isExportableFormat(string const & format) const
-{
-       typedef vector<Format const *> Formats;
-       Formats formats;
-       formats = exportableFormats(true);
-       Formats::const_iterator fit = formats.begin();
-       Formats::const_iterator end = formats.end();
-       for (; fit != end ; ++fit) {
-               if ((*fit)->name() == format)
-                       return true;
-       }
-       return false;
+       sort(result.begin(), result.end(), Format::formatSorter);
+       cached = result;
+       valid = true;
+       return cached;
 }
 
 
@@ -2516,7 +2690,7 @@ string BufferParams::getDefaultOutputFormat() const
                return default_output_format;
        if (isDocBook()
            || encoding().package() == Encoding::japanese) {
-               vector<Format const *> const formats = exportableFormats(true);
+               FormatList const & formats = exportableFormats(true);
                if (formats.empty())
                        return string();
                // return the first we find
@@ -2540,9 +2714,9 @@ Font const BufferParams::getFont() const
 }
 
 
-InsetQuotes::QuoteLanguage BufferParams::getQuoteStyle(string const & qs) const
+InsetQuotesParams::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
 {
-       return quoteslangtranslator().find(qs);
+       return quotesstyletranslator().find(qs);
 }
 
 
@@ -2926,7 +3100,7 @@ string const BufferParams::dvips_options() const
 }
 
 
-string const BufferParams::font_encoding() const
+string const BufferParams::main_font_encoding() const
 {
        return font_encodings().empty() ? "default" : font_encodings().back();
 }
@@ -3162,7 +3336,7 @@ string const BufferParams::loadFonts(LaTeXFeatures & features) const
        }
 
        // Tex Fonts
-       bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1");
+       bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
        bool const dryrun = features.runparams().dryrun;
        bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
        bool const nomath = (fontsMath() == "default");
@@ -3239,7 +3413,12 @@ bool BufferParams::addCiteEngine(vector<string> const & engine)
 
 string const & BufferParams::defaultBiblioStyle() const
 {
-       return documentClass().defaultBiblioStyle();
+       map<string, string> const & bs = documentClass().defaultBiblioStyle();
+       auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
+       if (cit != bs.end())
+               return cit->second;
+       else
+               return empty_string();
 }
 
 
@@ -3249,6 +3428,20 @@ bool const & BufferParams::fullAuthorList() const
 }
 
 
+string BufferParams::getCiteAlias(string const & s) const
+{
+       vector<string> commands =
+               documentClass().citeCommands(citeEngineType());
+       // If it is a real command, don't treat it as an alias
+       if (find(commands.begin(), commands.end(), s) != commands.end())
+               return string();
+       map<string,string> aliases = documentClass().citeCommandAliases();
+       if (aliases.find(s) != aliases.end())
+               return aliases[s];
+       return string();
+}
+
+
 void BufferParams::setCiteEngine(string const & engine)
 {
        clearCiteEngine();
@@ -3269,7 +3462,7 @@ vector<string> BufferParams::citeCommands() const
        vector<string> commands =
                documentClass().citeCommands(citeEngineType());
        if (commands.empty())
-               commands.push_back(default_style.cmd);
+               commands.push_back(default_style.name);
        return commands;
 }
 
@@ -3284,4 +3477,57 @@ vector<CitationStyle> BufferParams::citeStyles() const
        return styles;
 }
 
+
+string const BufferParams::bibtexCommand() const
+{
+       // Return document-specific setting if available
+       if (bibtex_command != "default")
+               return bibtex_command;
+
+       // If we have "default" in document settings, consult the prefs
+       // 1. Japanese (uses a specific processor)
+       if (encoding().package() == Encoding::japanese) {
+               if (lyxrc.jbibtex_command != "automatic")
+                       // Return the specified program, if "automatic" is not set
+                       return lyxrc.jbibtex_command;
+               else if (!useBiblatex()) {
+                       // With classic BibTeX, return pbibtex, jbibtex, bibtex
+                       if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
+                               return "pbibtex";
+                       if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
+                               return "jbibtex";
+                       return "bibtex";
+               }
+       }
+       // 2. All other languages
+       else if (lyxrc.bibtex_command != "automatic")
+               // Return the specified program, if "automatic" is not set
+               return lyxrc.bibtex_command;
+
+       // 3. Automatic: find the most suitable for the current cite framework
+       if (useBiblatex()) {
+               // For Biblatex, we prefer biber (also for Japanese)
+               // and fall back to bibtex8 and, as last resort, bibtex
+               if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
+                       return "biber";
+               else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
+                       return "bibtex8";
+       }
+       return "bibtex";
+}
+
+
+bool BufferParams::useBiblatex() const
+{
+       return theCiteEnginesList[citeEngine().list().front()]
+                       ->getCiteFramework() == "biblatex";
+}
+
+
+void BufferParams::invalidateConverterCache() const
+{
+       pimpl_->isExportCacheValid = false;
+       pimpl_->isViewCacheValid = false;
+}
+
 } // namespace lyx