X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FLaTeXFeatures.cpp;h=16ec4c19864517ca3e0c76aa66e652ad0b87a86f;hb=670efa8f646218f2a378f0cc614c4c37a9f6b89a;hp=d5a0b6f6b90043b7015f37d64dad51804ea5071b;hpb=a2e8cb758b70269da40d13d7b272d256a29a022a;p=lyx.git diff --git a/src/LaTeXFeatures.cpp b/src/LaTeXFeatures.cpp index d5a0b6f6b9..16ec4c1986 100644 --- a/src/LaTeXFeatures.cpp +++ b/src/LaTeXFeatures.cpp @@ -24,6 +24,7 @@ #include "Floating.h" #include "FloatList.h" #include "Language.h" +#include "LaTeXFonts.h" #include "LaTeXPackages.h" #include "Layout.h" #include "Lexer.h" @@ -65,7 +66,7 @@ static docstring const lyx_def = from_ascii( static docstring const lyx_hyperref_def = from_ascii( "\\providecommand{\\LyX}{\\texorpdfstring%\n" " {L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}\n" - " {LyX}}"); + " {LyX}}"); static docstring const noun_def = from_ascii( "\\newcommand{\\noun}[1]{\\textsc{#1}}"); @@ -183,36 +184,39 @@ static docstring const changetracking_dvipost_def = from_ascii( "\\dvipost{osend color pop}\n" "\\dvipost{cbstart color push Blue}\n" "\\dvipost{cbend color pop}\n" - "\\newcommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n" - "\\newcommand{\\lyxdeleted}[3]{%\n" + "\\DeclareRobustCommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n" + "\\DeclareRobustCommand{\\lyxdeleted}[3]{%\n" "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n"); static docstring const changetracking_xcolor_ulem_def = from_ascii( "%% Change tracking with ulem\n" - "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n" - "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n"); + "\\DeclareRobustCommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n" + "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n"); static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii( "%% Change tracking with ulem\n" - "\\newcommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n" - "\\newcommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n"); + "\\DeclareRobustCommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n" + "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n"); static docstring const changetracking_none_def = from_ascii( "\\newcommand{\\lyxadded}[3]{#3}\n" "\\newcommand{\\lyxdeleted}[3]{}\n"); +static docstring const textgreek_LGR_def = from_ascii( + "\\DeclareFontEncoding{LGR}{}{}\n"); static docstring const textgreek_def = from_ascii( "\\DeclareRobustCommand{\\greektext}{%\n" " \\fontencoding{LGR}\\selectfont\\def\\encodingdefault{LGR}}\n" "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n" - "\\DeclareFontEncoding{LGR}{}{}\n" - "\\DeclareTextSymbol{\\~}{LGR}{126}"); + "\\ProvideTextCommand{\\~}{LGR}[1]{\\char126#1}\n"); +static docstring const textcyr_T2A_def = from_ascii( + "\\InputIfFileExists{t2aenc.def}{}{%\n" + " \\errmessage{File `t2aenc.def' not found: Cyrillic script not supported}}\n"); static docstring const textcyr_def = from_ascii( "\\DeclareRobustCommand{\\cyrtext}{%\n" " \\fontencoding{T2A}\\selectfont\\def\\encodingdefault{T2A}}\n" - "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n" - "\\AtBeginDocument{\\DeclareFontEncoding{T2A}{}{}}\n"); + "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"); static docstring const lyxmathsym_def = from_ascii( "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n" @@ -265,17 +269,108 @@ static docstring const ogonek_def = from_ascii( " \\mathchar\"0\\hexnumber@\\symtipasymb0C}{#2}}\n" "\\newcommand{\\ogonek}[1]{\\mathpalette\\doogonek{#1}}\n"); +static docstring const lyxaccent_def = from_ascii( + "%% custom text accent \\LyxTextAccent[]{}{}\n" + "\\newcommand*{\\LyxTextAccent}[3][0ex]{%\n" + " \\hmode@bgroup\\ooalign{\\null#3\\crcr\\hidewidth\n" + " \\raise#1\\hbox{#2}\\hidewidth}\\egroup}\n" + "%% select a font size smaller than the current font size:\n" + "\\newcommand{\\LyxAccentSize}[1][\\sf@size]{%\n" + " \\check@mathfonts\\fontsize#1\\z@\\math@fontsfalse\\selectfont\n" + "}\n"); + +static docstring const textcommabelow_def = from_ascii( + "\\ProvideTextCommandDefault{\\textcommabelow}[1]{%%\n" + " \\LyxTextAccent[-.31ex]{\\LyxAccentSize,}{#1}}\n"); + +static docstring const textcommaabove_def = from_ascii( + "\\ProvideTextCommandDefault{\\textcommaabove}[1]{%%\n" + " \\LyxTextAccent[.5ex]{\\LyxAccentSize`}{#1}}\n"); + +static docstring const textcommaaboveright_def = from_ascii( + "\\ProvideTextCommandDefault{\\textcommaaboveright}[1]{%%\n" + " \\LyxTextAccent[.5ex]{\\LyxAccentSize\\ `}{#1}}\n"); + +// Baltic languages use a comma-accent instead of a cedilla +static docstring const textbaltic_def = from_ascii( + "%% use comma accent instead of cedilla for these characters:\n" + "\\DeclareTextCompositeCommand{\\c}{T1}{g}{\\textcommaabove{g}}\n" + "\\DeclareTextCompositeCommand{\\c}{T1}{G}{\\textcommabelow{G}}\n" + "\\DeclareTextCompositeCommand{\\c}{T1}{k}{\\textcommabelow{k}}\n" + "\\DeclareTextCompositeCommand{\\c}{T1}{K}{\\textcommabelow{K}}\n" + "\\DeclareTextCompositeCommand{\\c}{T1}{l}{\\textcommabelow{l}}\n" + "\\DeclareTextCompositeCommand{\\c}{T1}{L}{\\textcommabelow{L}}\n" + "\\DeclareTextCompositeCommand{\\c}{T1}{n}{\\textcommabelow{n}}\n" + "\\DeclareTextCompositeCommand{\\c}{T1}{N}{\\textcommabelow{N}}\n" + "\\DeclareTextCompositeCommand{\\c}{T1}{r}{\\textcommabelow{r}}\n" + "\\DeclareTextCompositeCommand{\\c}{T1}{R}{\\textcommabelow{R}}\n"); + static docstring const lyxref_def = from_ascii( - "\\RS@ifundefined{subref}\n" - " {\\def\\RSsubtxt{section~}\\newref{sub}{name = \\RSsubtxt}}\n" + "\\RS@ifundefined{subsecref}\n" + " {\\newref{subsec}{name = \\RSsectxt}}\n" " {}\n" "\\RS@ifundefined{thmref}\n" " {\\def\\RSthmtxt{theorem~}\\newref{thm}{name = \\RSthmtxt}}\n" " {}\n" "\\RS@ifundefined{lemref}\n" - " {\\def\\RSlemtxt{lemma~}\\newref{lem}{name = \\RSlemtxt}}\n" + " {\\def\\RSlemtxt{lemma~}\\newref{lem}{name = \\RSlemtxt}}\n" " {}\n"); +// Make sure the columns are also outputed as rtl +static docstring const rtloutputdblcol_def = from_ascii( + "\\def\\@outputdblcol{%\n" + " \\if@firstcolumn\n" + " \\global \\@firstcolumnfalse\n" + " \\global \\setbox\\@leftcolumn \\box\\@outputbox\n" + " \\else\n" + " \\global \\@firstcolumntrue\n" + " \\setbox\\@outputbox \\vbox {%\n" + " \\hb@xt@\\textwidth {%\n" + " \\kern\\textwidth \\kern-\\columnwidth %**\n" + " \\hb@xt@\\columnwidth {%\n" + " \\box\\@leftcolumn \\hss}%\n" + " \\kern-\\textwidth %**\n" + " \\hfil\n" + " {\\normalcolor\\vrule \\@width\\columnseprule}%\n" + " \\hfil\n" + " \\kern-\\textwidth %**\n" + " \\hb@xt@\\columnwidth {%\n" + " \\box\\@outputbox \\hss}%\n" + " \\kern-\\columnwidth \\kern\\textwidth %**\n" + " }%\n" + " }%\n" + " \\@combinedblfloats\n" + " \\@outputpage\n" + " \\begingroup\n" + " \\@dblfloatplacement\n" + " \\@startdblcolumn\n" + " \\@whilesw\\if@fcolmade \\fi\n" + " {\\@outputpage\n" + " \\@startdblcolumn}%\n" + " \\endgroup\n" + " \\fi\n" + "}\n" + "\\@mparswitchtrue\n"); + + +///////////////////////////////////////////////////////////////////// +// +// LyXHTML strings +// +///////////////////////////////////////////////////////////////////// + +static docstring const lyxnoun_style = from_ascii( + "dfn.lyxnoun {\n" + " font-variant: small-caps;\n" + "}\n"); + + +// this is how it normally renders, but it might not always do so. +static docstring const lyxstrikeout_style = from_ascii( + "del.strikeout {\n" + " text-decoration: line-through;\n" + "}\n"); + ///////////////////////////////////////////////////////////////////// // @@ -290,35 +385,70 @@ LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p, {} -bool LaTeXFeatures::useBabel() const +LaTeXFeatures::LangPackage LaTeXFeatures::langPackage() const { - if (usePolyglossia()) - return false; - if (bufferParams().lang_package == "default") - return (lyxrc.language_package_selection != LyXRC::LP_NONE) - || (bufferParams().language->lang() != lyxrc.default_language - && !bufferParams().language->babel().empty()) - || this->hasLanguages(); - return (bufferParams().lang_package != "none") - || (bufferParams().language->lang() != lyxrc.default_language - && !bufferParams().language->babel().empty()) - || this->hasLanguages(); -} + string const local_lp = bufferParams().lang_package; + + // Locally, custom is just stored as a string + // in bufferParams().lang_package. + if (local_lp != "auto" + && local_lp != "babel" + && local_lp != "default" + && local_lp != "none") + return LANG_PACK_CUSTOM; + + if (local_lp == "none") + return LANG_PACK_NONE; + + /* If "auto" is selected, we load polyglossia with non-TeX fonts, + * else we select babel. + * If babel is selected (either directly or via the "auto" + * mechanism), we really do only require it if we have + * a language that needs it. + */ + bool const polyglossia_required = + params_.useNonTeXFonts + && isAvailable("polyglossia") + && !isProvided("babel") + && this->hasOnlyPolyglossiaLanguages(); + bool const babel_required = + !bufferParams().language->babel().empty() + || !this->getBabelLanguages().empty(); + + if (local_lp == "auto") { + // polyglossia requirement has priority over babel + if (polyglossia_required) + return LANG_PACK_POLYGLOSSIA; + else if (babel_required) + return LANG_PACK_BABEL; + } + if (local_lp == "babel") { + if (babel_required) + return LANG_PACK_BABEL; + } -bool LaTeXFeatures::usePolyglossia() const -{ - if (bufferParams().lang_package == "default") - return (lyxrc.language_package_selection == LyXRC::LP_AUTO) - && isRequired("polyglossia") - && isAvailable("polyglossia") - && !params_.documentClass().provides("babel") - && this->hasPolyglossiaLanguages(); - return (bufferParams().lang_package == "auto") - && isRequired("polyglossia") - && isAvailable("polyglossia") - && !params_.documentClass().provides("babel") - && this->hasPolyglossiaLanguages(); + if (local_lp == "default") { + switch (lyxrc.language_package_selection) { + case LyXRC::LP_AUTO: + // polyglossia requirement has priority over babel + if (polyglossia_required) + return LANG_PACK_POLYGLOSSIA; + else if (babel_required) + return LANG_PACK_BABEL; + break; + case LyXRC::LP_BABEL: + if (babel_required) + return LANG_PACK_BABEL; + break; + case LyXRC::LP_CUSTOM: + return LANG_PACK_CUSTOM; + case LyXRC::LP_NONE: + return LANG_PACK_NONE; + } + } + + return LANG_PACK_NONE; } @@ -335,9 +465,14 @@ void LaTeXFeatures::require(set const & names) void LaTeXFeatures::useLayout(docstring const & layoutname) +{ + useLayout(layoutname, 0); +} + + +void LaTeXFeatures::useLayout(docstring const & layoutname, int level) { // Some code to avoid loops in dependency definition - static int level = 0; const int maxlevel = 30; if (level > maxlevel) { lyxerr << "LaTeXFeatures::useLayout: maximum level of " @@ -357,9 +492,7 @@ void LaTeXFeatures::useLayout(docstring const & layoutname) require(layout.requires()); if (!layout.depends_on().empty()) { - ++level; - useLayout(layout.depends_on()); - --level; + useLayout(layout.depends_on(), level + 1); } usedLayouts_.push_back(layoutname); } else { @@ -367,8 +500,6 @@ void LaTeXFeatures::useLayout(docstring const & layoutname) << to_utf8(layoutname) << "' does not exist in this class" << endl; } - - --level; } @@ -396,9 +527,42 @@ bool LaTeXFeatures::isRequired(string const & name) const } +bool LaTeXFeatures::isProvided(string const & name) const +{ + if (params_.useNonTeXFonts) + return params_.documentClass().provides(name); + + bool const ot1 = (params_.font_encoding() == "default" + || params_.font_encoding() == "OT1"); + bool const complete = (params_.fontsSans() == "default" + && params_.fontsTypewriter() == "default"); + bool const nomath = (params_.fontsMath() == "default"); + return params_.documentClass().provides(name) + || theLaTeXFonts().getLaTeXFont( + from_ascii(params_.fontsRoman())).provides(name, ot1, + complete, + nomath) + || theLaTeXFonts().getLaTeXFont( + from_ascii(params_.fontsSans())).provides(name, ot1, + complete, + nomath) + || theLaTeXFonts().getLaTeXFont( + from_ascii(params_.fontsTypewriter())).provides(name, ot1, + complete, + nomath) + || theLaTeXFonts().getLaTeXFont( + from_ascii(params_.fontsMath())).provides(name, ot1, + complete, + nomath); + // TODO: "textbaltic" provided, if the font-encoding is "L7x" + // "textgreek" provided, if a language with font-encoding LGR is used in the document + // "textcyr" provided, if a language with font-encoding T2A is used in the document +} + + bool LaTeXFeatures::mustProvide(string const & name) const { - return isRequired(name) && !params_.documentClass().provides(name); + return isRequired(name) && !isProvided(name); } @@ -415,11 +579,12 @@ bool LaTeXFeatures::isAvailable(string const & name) } -void LaTeXFeatures::addPreambleSnippet(string const & preamble) +void LaTeXFeatures::addPreambleSnippet(string const & preamble, + bool allowdupes) { SnippetList::const_iterator begin = preamble_snippets_.begin(); SnippetList::const_iterator end = preamble_snippets_.end(); - if (find(begin, end, preamble) == end) + if (allowdupes || find(begin, end, preamble) == end) preamble_snippets_.push_back(preamble); } @@ -451,10 +616,10 @@ void LaTeXFeatures::useFloat(string const & name, bool subfloat) void LaTeXFeatures::useLanguage(Language const * lang) { - if (!lang->babel().empty()) + if (!lang->babel().empty() || !lang->polyglossia().empty()) UsedLanguages_.insert(lang); - if (lang->lang() == "vietnamese") - require("vietnamese"); + if (!lang->requires().empty()) + require(lang->requires()); // CJK languages do not have a babel name. // They use the CJK package if (lang->encoding()->package() == Encoding::CJK) @@ -477,8 +642,12 @@ bool LaTeXFeatures::hasLanguages() const } -bool LaTeXFeatures::hasPolyglossiaLanguages() const +bool LaTeXFeatures::hasOnlyPolyglossiaLanguages() const { + // first the main language + if (params_.language->polyglossia().empty()) + return false; + // now the secondary languages LanguageList::const_iterator const begin = UsedLanguages_.begin(); for (LanguageList::const_iterator cit = begin; cit != UsedLanguages_.end(); @@ -490,16 +659,38 @@ bool LaTeXFeatures::hasPolyglossiaLanguages() const } -string LaTeXFeatures::getLanguages() const +bool LaTeXFeatures::hasPolyglossiaExclusiveLanguages() const +{ + // first the main language + if (params_.language->isPolyglossiaExclusive()) + return true; + // now the secondary languages + LanguageList::const_iterator const begin = UsedLanguages_.begin(); + for (LanguageList::const_iterator cit = begin; + cit != UsedLanguages_.end(); + ++cit) { + if ((*cit)->isPolyglossiaExclusive()) + return true; + } + return false; +} + + +string LaTeXFeatures::getBabelLanguages() const { ostringstream languages; + bool first = true; LanguageList::const_iterator const begin = UsedLanguages_.begin(); for (LanguageList::const_iterator cit = begin; cit != UsedLanguages_.end(); ++cit) { - if (cit != begin) + if ((*cit)->babel().empty()) + continue; + if (!first) languages << ','; + else + first = false; languages << (*cit)->babel(); } return languages.str(); @@ -536,6 +727,31 @@ set LaTeXFeatures::getEncodingSet(string const & doc_encoding) const return encodings; } + +void LaTeXFeatures::getFontEncodings(vector & encodings) const +{ + // these must be loaded if glyphs of this script are used + // unless a language providing them is used in the document + // FIXME: currently the option is written twice in this case + if (mustProvide("textgreek")) + encodings.insert(encodings.begin(), "LGR"); + if (mustProvide("textcyr")) + encodings.insert(encodings.begin(), "T2A"); + + LanguageList::const_iterator it = UsedLanguages_.begin(); + LanguageList::const_iterator end = UsedLanguages_.end(); + for (; it != end; ++it) + if (!(*it)->fontenc().empty() + && ascii_lowercase((*it)->fontenc()) != "none") { + vector extraencs = getVectorFromString((*it)->fontenc()); + vector::const_iterator fit = extraencs.begin(); + for (; fit != extraencs.end(); ++fit) { + if (find(encodings.begin(), encodings.end(), *fit) == encodings.end()) + encodings.insert(encodings.begin(), *fit); + } + } +} + namespace { char const * simplefeatures[] = { @@ -562,22 +778,19 @@ char const * simplefeatures[] = { "fancybox", "calc", "units", - "tipa", - "tipx", "framed", "soul", "textcomp", "pmboxdraw", "bbding", "ifsym", - "marvosym", "txfonts", "pxfonts", "mathdesign", "mathrsfs", "mathabx", "mathtools", - "cancel", + // "cancel", "ascii", "url", "covington", @@ -591,10 +804,40 @@ char const * simplefeatures[] = { "pdfpages", "amscd", "slashed", + "multicol", "multirow", - "tfrupee" + "tfrupee", + "shapepar", + "rsphrase", + "hpstatement", + "algorithm2e", + "sectionbox", + "tcolorbox", + "pdfcomment", + "fixme", + "todonotes", + "forest", + "varwidth" +}; + +char const * bibliofeatures[] = { + // Known bibliography packages (will be loaded before natbib) + "achicago", + "apacite", + "apalike", + "astron", + "authordate1-4", + "babelbib", + "bibgerm", + "chicago", + "chscite", + "harvard", + "mslapa", + "named" }; +int const nb_bibliofeatures = sizeof(bibliofeatures) / sizeof(char const *); + int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *); } @@ -660,10 +903,25 @@ string const LaTeXFeatures::getColorOptions() const } +string const LaTeXFeatures::getPackageOptions() const +{ + ostringstream packageopts; + // Output all the package option stuff we have been asked to do. + map::const_iterator it = + params_.documentClass().packageOptions().begin(); + map::const_iterator en = + params_.documentClass().packageOptions().end(); + for (; it != en; ++it) + if (mustProvide(it->first)) + packageopts << "\\PassOptionsToPackage{" << it->second << "}" + << "{" << it->first << "}\n"; + return packageopts.str(); +} + + string const LaTeXFeatures::getPackages() const { ostringstream packages; - DocumentClass const & tclass = params_.documentClass(); // FIXME: currently, we can only load packages and macros known // to LyX. @@ -671,45 +929,47 @@ string const LaTeXFeatures::getPackages() const // also unknown packages can be requested. They are silently // swallowed now. We should change this eventually. - // // These are all the 'simple' includes. i.e // packages which we just \usepackage{package} - // for (int i = 0; i < nb_simplefeatures; ++i) { if (mustProvide(simplefeatures[i])) - packages << "\\usepackage{" - << simplefeatures[i] << "}\n"; + packages << "\\usepackage{" << simplefeatures[i] << "}\n"; } - // // The rest of these packages are somewhat more complicated // than those above. - // - // if fontspec is used, AMS packages have to be loaded before - // fontspec (in BufferParams) + // The tipa package and its extensions (tipx, tone) must not + // be loaded with non-TeX fonts, since fontspec includes the + // respective macros + if (mustProvide("tipa") && !params_.useNonTeXFonts) + packages << "\\usepackage{tipa}\n"; + if (mustProvide("tipx") && !params_.useNonTeXFonts) + packages << "\\usepackage{tipx}\n"; + if (mustProvide("tone") && !params_.useNonTeXFonts) + packages << "\\usepackage{tone}\n"; + + // if fontspec or newtxmath is used, AMS packages have to be loaded + // before fontspec (in BufferParams) string const amsPackages = loadAMSPackages(); - if (!params_.useNonTeXFonts && !amsPackages.empty()) + bool const ot1 = (params_.font_encoding() == "default" || params_.font_encoding() == "OT1"); + bool const use_newtxmath = + theLaTeXFonts().getLaTeXFont(from_ascii(params_.fontsMath())).getUsedPackage( + ot1, false, false) == "newtxmath"; + + if (!params_.useNonTeXFonts && !use_newtxmath && !amsPackages.empty()) packages << amsPackages; - // fixltx2e must be loaded after amsthm, since amsthm produces an error with - // the redefined \[ command (bug 7233). Load it as early as possible, since - // other packages might profit from it. - if (mustProvide("fixltx2e")) - packages << "\\usepackage{fixltx2e}\n"; + if (mustProvide("cancel") && + params_.use_package("cancel") != BufferParams::package_off) + packages << "\\usepackage{cancel}\n"; - // wasysym is a simple feature, but it must be after amsmath if both - // are used - // wasysym redefines some integrals (e.g. iint) from amsmath. That - // leads to inconsistent integrals. We only load this package if - // the document does not contain integrals (then isRequired("esint") - // is false) or if esint is used, since esint redefines all relevant - // integral symbols from wasysym and amsmath. - // See http://www.lyx.org/trac/ticket/1942 - if (mustProvide("wasysym") && - params_.use_package("wasysym") != BufferParams::package_off && - (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint"))) - packages << "\\usepackage{wasysym}\n"; + // marvosym and bbding both define the \Cross macro + if (mustProvide("marvosym")) { + if (mustProvide("bbding")) + packages << "\\let\\Cross\\relax\n"; + packages << "\\usepackage{marvosym}\n"; + } // accents must be loaded after amsmath if (mustProvide("accents") && @@ -726,6 +986,15 @@ string const LaTeXFeatures::getPackages() const params_.use_package("yhmath") != BufferParams::package_off) packages << "\\usepackage{yhmath}\n"; + // stmaryrd must be loaded after amsmath + if (mustProvide("stmaryrd") && + params_.use_package("stmaryrd") != BufferParams::package_off) + packages << "\\usepackage{stmaryrd}\n"; + + if (mustProvide("stackrel") && + params_.use_package("stackrel") != BufferParams::package_off) + packages << "\\usepackage{stackrel}\n"; + if (mustProvide("undertilde") && params_.use_package("undertilde") != BufferParams::package_off) packages << "\\usepackage{undertilde}\n"; @@ -734,9 +1003,9 @@ string const LaTeXFeatures::getPackages() const // makeidx.sty if (isRequired("makeidx") || isRequired("splitidx")) { - if (!tclass.provides("makeidx") && !isRequired("splitidx")) + if (!isProvided("makeidx") && !isRequired("splitidx")) packages << "\\usepackage{makeidx}\n"; - if (!tclass.provides("splitidx") && isRequired("splitidx")) + if (mustProvide("splitidx")) packages << "\\usepackage{splitidx}\n"; packages << "\\makeindex\n"; } @@ -756,20 +1025,52 @@ string const LaTeXFeatures::getPackages() const packages << "\\usepackage[ps,mover]{lyxskak}\n"; // setspace.sty - if (mustProvide("setspace") && !tclass.provides("SetSpace")) + if (mustProvide("setspace") && !isProvided("SetSpace")) packages << "\\usepackage{setspace}\n"; - // esint must be after amsmath and wasysym, since it will redeclare - // inconsistent integral symbols + // we need to assure that mhchem is loaded before esint and every other + // package that redefines command of amsmath because mhchem loads amlatex + // (this info is from the author of mhchem from June 2013) + if (mustProvide("mhchem") && + params_.use_package("mhchem") != BufferParams::package_off) + packages << "\\PassOptionsToPackage{version=3}{mhchem}\n" + "\\usepackage{mhchem}\n"; + + // wasysym is a simple feature, but it must be after amsmath if both + // are used + // wasysym redefines some integrals (e.g. iint) from amsmath. That + // leads to inconsistent integrals. We only load this package if + // the document does not contain integrals (then isRequired("esint") + // is false) or if esint is used, since esint redefines all relevant + // integral symbols from wasysym and amsmath. + // See http://www.lyx.org/trac/ticket/1942 + if (mustProvide("wasysym") && + params_.use_package("wasysym") != BufferParams::package_off && + (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint"))) + packages << "\\usepackage{wasysym}\n"; + + // esint must be after amsmath (and packages requiring amsmath, like mhchem) + // and wasysym, since it will redeclare inconsistent integral symbols if (mustProvide("esint") && params_.use_package("esint") != BufferParams::package_off) packages << "\\usepackage{esint}\n"; + // Known bibliography packages (simple \usepackage{package}) + for (int i = 0; i < nb_bibliofeatures; ++i) { + if (mustProvide(bibliofeatures[i])) + packages << "\\usepackage{" + << bibliofeatures[i] << "}\n"; + } + + // Compatibility between achicago and natbib + if (mustProvide("achicago") && mustProvide("natbib")) + packages << "\\let\\achicagobib\\thebibliography\n"; + // natbib.sty // Some classes load natbib themselves, but still allow (or even require) // plain numeric citations (ReVTeX is such a case, see bug 5182). // This special case is indicated by the "natbib-internal" key. - if (mustProvide("natbib") && !tclass.provides("natbib-internal")) { + if (mustProvide("natbib") && !isProvided("natbib-internal")) { packages << "\\usepackage["; if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL) packages << "numbers"; @@ -778,19 +1079,29 @@ string const LaTeXFeatures::getPackages() const packages << "]{natbib}\n"; } + // Compatibility between achicago and natbib + if (mustProvide("achicago") && mustProvide("natbib")) { + packages << "\\let\\thebibliography\\achicagobib\n"; + packages << "\\let\\SCcite\\astroncite\n"; + packages << "\\let\\UnexpandableProtect\\protect\n"; + } + // jurabib -- we need version 0.6 at least. if (mustProvide("jurabib")) packages << "\\usepackage{jurabib}[2004/01/25]\n"; + // opcit -- we pass custombst as we output \bibliographystyle ourselves + if (mustProvide("opcit")) { + if (isRequired("hyperref")) + packages << "\\usepackage[custombst,hyperref]{opcit}\n"; + else + packages << "\\usepackage[custombst]{opcit}\n"; + } + // xargs -- we need version 1.09 at least if (mustProvide("xargs")) packages << "\\usepackage{xargs}[2008/03/08]\n"; - // bibtopic -- the dot provides the aux file naming which - // LyX can detect. - if (mustProvide("bibtopic")) - packages << "\\usepackage[dot]{bibtopic}\n"; - if (mustProvide("xy")) packages << "\\usepackage[all]{xy}\n"; @@ -801,11 +1112,6 @@ string const LaTeXFeatures::getPackages() const packages << "\\PassOptionsToPackage{normalem}{ulem}\n" "\\usepackage{ulem}\n"; - if (mustProvide("mhchem") && - params_.use_package("mhchem") != BufferParams::package_off) - packages << "\\PassOptionsToPackage{version=3}{mhchem}\n" - "\\usepackage{mhchem}\n"; - if (mustProvide("nomencl")) { // Make it work with the new and old version of the package, // but don't use the compatibility option since it is @@ -821,6 +1127,16 @@ string const LaTeXFeatures::getPackages() const if (mustProvide("subscript") && !isRequired("fixltx2e")) packages << "\\usepackage{subscript}\n"; + // footmisc must be loaded after setspace + // Set options here, load the package after the user preamble to + // avoid problems with manual loaded footmisc. + if (mustProvide("footmisc")) + packages << "\\PassOptionsToPackage{stable}{footmisc}\n"; + + if (mustProvide("microtype")){ + packages << "\\usepackage{microtype}\n"; + } + return packages.str(); } @@ -877,21 +1193,35 @@ docstring const LaTeXFeatures::getMacros() const macros << lyxarrow_def << '\n'; if (!usePolyglossia() && mustProvide("textgreek")) { - // Avoid a LaTeX error if times fonts are used and the grtimes - // package is installed but actual fonts are not (bug 6469). - if (params_.fonts_roman == "times") - macros << subst(textgreek_def, - from_ascii("\\greektext #1"), - from_ascii("%\n \\IfFileExists" - "{grtm10.tfm}{}{\\fontfamily" - "{cmr}}\\greektext #1")) - << '\n'; - else - macros << textgreek_def << '\n'; + // ensure LGR font encoding is defined also if fontenc is not loaded by LyX + if (params_.font_encoding() == "default") + macros << textgreek_LGR_def; + macros << textgreek_def << '\n'; } - if (!usePolyglossia() && mustProvide("textcyr")) + if (!usePolyglossia() && mustProvide("textcyr")) { + // ensure T2A font encoding is set up also if fontenc is not loaded by LyX + if (params_.font_encoding() == "default") + macros << textcyr_T2A_def; macros << textcyr_def << '\n'; + } + + // non-standard text accents: + if (mustProvide("textcommaabove") || mustProvide("textcommaaboveright") || + mustProvide("textcommabelow") || mustProvide("textbaltic")) + macros << lyxaccent_def; + + if (mustProvide("textcommabelow") || mustProvide("textbaltic")) + macros << textcommabelow_def << '\n'; + + if (mustProvide("textcommaabove") || mustProvide("textbaltic")) + macros << textcommaabove_def << '\n'; + + if (mustProvide("textcommaaboveright")) + macros << textcommaaboveright_def << '\n'; + + if (mustProvide("textbaltic")) + macros << textbaltic_def << '\n'; if (mustProvide("lyxmathsym")) macros << lyxmathsym_def << '\n'; @@ -997,6 +1327,9 @@ docstring const LaTeXFeatures::getMacros() const if (mustProvide("ct-none")) macros << changetracking_none_def; + if (mustProvide("rtloutputdblcol")) + macros << rtloutputdblcol_def; + return macros.str(); } @@ -1013,7 +1346,10 @@ string const LaTeXFeatures::getBabelPresettings() const if (!params_.language->babel_presettings().empty()) tmp << params_.language->babel_presettings() << '\n'; - return tmp.str(); + if (!contains(tmp.str(), '@')) + return tmp.str(); + + return "\\makeatletter\n" + tmp.str() + "\\makeatother\n"; } @@ -1029,7 +1365,10 @@ string const LaTeXFeatures::getBabelPostsettings() const if (!params_.language->babel_postsettings().empty()) tmp << params_.language->babel_postsettings() << '\n'; - return tmp.str(); + if (!contains(tmp.str(), '@')) + return tmp.str(); + + return "\\makeatletter\n" + tmp.str() + "\\makeatother\n"; } @@ -1051,8 +1390,6 @@ bool LaTeXFeatures::needBabelLangOptions() const string const LaTeXFeatures::loadAMSPackages() const { ostringstream tmp; - if (mustProvide("amsthm")) - tmp << "\\usepackage{amsthm}\n"; if (mustProvide("amsmath") && params_.use_package("amsmath") != BufferParams::package_off) { @@ -1065,8 +1402,11 @@ string const LaTeXFeatures::loadAMSPackages() const tmp << "\\usepackage{amstext}\n"; } + if (mustProvide("amsthm")) + tmp << "\\usepackage{amsthm}\n"; + if (mustProvide("amssymb") - || params_.use_package("amsmath") == BufferParams::package_on) + && params_.use_package("amssymb") != BufferParams::package_off) tmp << "\\usepackage{amssymb}\n"; return tmp.str(); @@ -1131,6 +1471,13 @@ docstring const LaTeXFeatures::getTClassHTMLStyles() const DocumentClass const & tclass = params_.documentClass(); odocstringstream tcpreamble; + if (mustProvide("noun")) + tcpreamble << lyxnoun_style; + // this isn't exact, but it won't hurt that much if it + // wasn't for this. + if (mustProvide("ulem")) + tcpreamble << lyxstrikeout_style; + tcpreamble << tclass.htmlstyles(); list::const_iterator cit = usedLayouts_.begin(); @@ -1153,6 +1500,7 @@ docstring const LaTeXFeatures::getTClassHTMLStyles() const namespace { + docstring const getFloatI18nPreamble(docstring const & type, docstring const & name, Language const * lang, Encoding const & enc, bool const polyglossia) @@ -1185,7 +1533,8 @@ docstring const getFloatI18nPreamble(docstring const & type, docstring const i18npreamble(docstring const & templ, Language const * lang, - Encoding const & enc, bool const polyglossia) + Encoding const & enc, bool const polyglossia, + bool const need_fixedwidth) { if (templ.empty()) return templ; @@ -1197,6 +1546,24 @@ docstring const i18npreamble(docstring const & templ, Language const * lang, string const langenc = lang->encoding()->iconvName(); string const texenc = lang->encoding()->latexName(); string const bufenc = enc.iconvName(); + Encoding const * testenc(&enc); + bool lang_fallback = false; + bool ascii_fallback = false; + if (need_fixedwidth && !enc.hasFixedWidth()) { + if (lang->encoding()->hasFixedWidth()) { + testenc = lang->encoding(); + lang_fallback = true; + } else { + // We need a fixed width encoding, but both the buffer + // encoding and the language encoding are variable + // width. As a last fallback, try to convert to pure + // ASCII using the LaTeX commands defined in unicodesymbols. + testenc = encodings.fromLyXName("ascii"); + if (!testenc) + return docstring(); + ascii_fallback = true; + } + } // First and second character of plane 15 (Private Use Area) string const s1 = "\xf3\xb0\x80\x80"; // U+F0000 string const s2 = "\xf3\xb0\x80\x81"; // U+F0001 @@ -1210,16 +1577,18 @@ docstring const i18npreamble(docstring const & templ, Language const * lang, docstring const name = lang->translateLayout(key); // Check whether name can be encoded in the buffer encoding bool encodable = true; - for (size_t i = 0; i < name.size(); ++i) { - if (!enc.encodable(name[i])) { + for (size_t i = 0; i < name.size() && encodable; ++i) + if (!testenc->encodable(name[i])) encodable = false; - break; - } - } - string const translated = encodable ? to_utf8(name) - : "\\inputencoding{" + texenc + "}" - + s1 + langenc + s2 + to_utf8(name) - + s1 + bufenc + s2; + string translated; + if (encodable && !lang_fallback) + translated = to_utf8(name); + else if (ascii_fallback) + translated = to_ascii(testenc->latexString(name).first); + else + translated = "\\inputencoding{" + texenc + "}" + + s1 + langenc + s2 + to_utf8(name) + + s1 + bufenc + s2; preamble = subst(preamble, sub.str(), translated); } return from_utf8(preamble); @@ -1244,20 +1613,20 @@ docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_po snippets.insert(i18npreamble(tclass[*cit].langpreamble(), buffer().language(), buffer().params().encoding(), - use_polyglossia)); + use_polyglossia, false)); // commands for language changing (for multilanguage documents) if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) { snippets.insert(i18npreamble( tclass[*cit].babelpreamble(), buffer().language(), buffer().params().encoding(), - use_polyglossia)); + use_polyglossia, false)); for (lang_it lit = lbeg; lit != lend; ++lit) snippets.insert(i18npreamble( tclass[*cit].babelpreamble(), *lit, buffer().params().encoding(), - use_polyglossia)); + use_polyglossia, false)); } } if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) { @@ -1305,24 +1674,31 @@ docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_po TextClass::InsetLayouts::const_iterator it = ils.find(*cit); if (it == ils.end()) continue; + // The listings package does not work with variable width + // encodings, only with fixed width encodings. Therefore we + // need to force a fixed width encoding for + // \lstlistlistingname and \lstlistingname (bug 9382). + // This needs to be consistent with InsetListings::latex(). + bool const need_fixedwidth = !runparams_.isFullUnicode() && + it->second.fixedwidthpreambleencoding(); // language dependent commands (once per document) snippets.insert(i18npreamble(it->second.langpreamble(), buffer().language(), buffer().params().encoding(), - use_polyglossia)); + use_polyglossia, need_fixedwidth)); // commands for language changing (for multilanguage documents) if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) { snippets.insert(i18npreamble( it->second.babelpreamble(), buffer().language(), buffer().params().encoding(), - use_polyglossia)); + use_polyglossia, need_fixedwidth)); for (lang_it lit = lbeg; lit != lend; ++lit) snippets.insert(i18npreamble( it->second.babelpreamble(), *lit, buffer().params().encoding(), - use_polyglossia)); + use_polyglossia, need_fixedwidth)); } } @@ -1457,7 +1833,8 @@ void LaTeXFeatures::getFloatDefinitions(odocstream & os) const // effect. (Lgb) } if (cit->second) - os << "\n\\newsubfloat{" << from_ascii(fl.floattype()) << "}\n"; + // The subfig package is loaded later + os << "\n\\AtBeginDocument{\\newsubfloat{" << from_ascii(fl.floattype()) << "}}\n"; } } @@ -1469,10 +1846,23 @@ void LaTeXFeatures::resolveAlternatives() vector const alternatives = getVectorFromString(*it, "|"); vector::const_iterator const end = alternatives.end(); vector::const_iterator ita = alternatives.begin(); + // Is any alternative already required? => use that for (; ita != end; ++ita) { if (isRequired(*ita)) break; } + // Is any alternative available? => use the first one + // (bug 9498) + if (ita == end) { + for (ita = alternatives.begin(); ita != end; ++ita) { + if (isAvailable(*ita)) { + require(*ita); + break; + } + } + } + // This will not work, but not requiring something + // would be more confusing if (ita == end) require(alternatives.front()); features_.erase(it);