X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FLaTeXFeatures.cpp;h=5f83283460ddd320ffaa095e5db42d52660c3957;hb=79cf3f5ec1088e7de988e889247ec300d42fb70b;hp=924308c50c94e1d5886d78fbeb799e5bc13ce81b;hpb=a2e6fc773a85787b70ed9c69581a20103a048cb8;p=lyx.git diff --git a/src/LaTeXFeatures.cpp b/src/LaTeXFeatures.cpp index 924308c50c..5f83283460 100644 --- a/src/LaTeXFeatures.cpp +++ b/src/LaTeXFeatures.cpp @@ -30,6 +30,8 @@ #include "Lexer.h" #include "LyXRC.h" #include "TextClass.h" +#include "TexRow.h" +#include "texstream.h" #include "insets/InsetLayout.h" @@ -63,10 +65,14 @@ namespace lyx { static docstring const lyx_def = from_ascii( "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}"); +static docstring const lyx_rtl_def = from_ascii( + "\\let\\@@LyX\\LyX\n" + "\\def\\LyX{\\@ensure@LTR{\\@@LyX}}"); + 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}}"); @@ -77,6 +83,15 @@ static docstring const lyxarrow_def = from_ascii( "{\\leavevmode\\,$\\triangleleft$\\,\\allowbreak}\n" "{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}}"); +// ZERO WIDTH SPACE (ZWSP) is actually not a space character +// but marks a line break opportunity. Several commands provide a +// line break opportunity. They differ in side-effects: +// \allowbreak prevents hyphenation after hyphen or dash + ZWSP +// \linebreak[] takes an optional argument denoting "urgency". +// The \LyXZeroWidthSpace wrapper allows customization in the preamble. +static docstring const lyxZWSP_def = from_ascii( + "\\newcommand*\\LyXZeroWidthSpace{\\hspace{0pt}}"); + // for quotes without babel. This does not give perfect results, but // anybody serious about non-english quotes should use babel (JMarc). @@ -116,6 +131,25 @@ static docstring const guilsinglright_def = from_ascii( " {\\usefont{U}{lasy}{m}{n}\\char'51}%\n" "}"); +static docstring const textquotedbl_def = from_ascii( + "\\DeclareTextSymbolDefault{\\textquotedbl}{T1}"); + +static docstring const textquotedblp_xetex_def = from_ascii( + "\\providecommand\\textquotedblplain{%\n" + " \\bgroup\\addfontfeatures{Mapping=}\\char34\\egroup}"); + +static docstring const textquotedblp_luatex_def = from_ascii( + "\\providecommand\\textquotedblplain{%\n" + " \\bgroup\\addfontfeatures{RawFeature=-tlig}\\char34\\egroup}"); + +static docstring const textquotesinglep_xetex_def = from_ascii( + "\\providecommand\\textquotesingleplain{%\n" + " \\bgroup\\addfontfeatures{Mapping=}\\char39\\egroup}"); + +static docstring const textquotesinglep_luatex_def = from_ascii( + "\\providecommand\\textquotesingleplain{%\n" + " \\bgroup\\addfontfeatures{RawFeature=-tlig}\\char39\\egroup}"); + static docstring const paragraphleftindent_def = from_ascii( "\\newenvironment{LyXParagraphLeftIndent}[1]%\n" "{\n" @@ -191,29 +225,44 @@ static docstring const changetracking_dvipost_def = from_ascii( static docstring const changetracking_xcolor_ulem_def = from_ascii( "%% Change tracking with ulem\n" "\\DeclareRobustCommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n" - "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n"); + "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\lyxsout{#3}}}\n" + "\\DeclareRobustCommand{\\lyxsout}[1]{\\ifx\\\\#1\\else\\sout{#1}\\fi}\n"); static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii( "%% Change tracking with ulem\n" "\\DeclareRobustCommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n" - "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n"); + "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\lyxsout{#3}}{}}}\n" + "\\DeclareRobustCommand{\\lyxsout}[1]{\\ifx\\\\#1\\else\\sout{#1}\\fi}\n"); + +static docstring const changetracking_tikz_math_sout_def = from_ascii( + "%% Strike out display math with tikz\n" + "\\usepackage{tikz}\n" + "\\usetikzlibrary{calc}\n" + "\\newcommand{\\lyxmathsout}[1]{%\n" + " \\tikz[baseline=(math.base)]{\n" + " \\node[inner sep=0pt,outer sep=0pt](math){#1};\n" + " \\draw($(math.south west)+(2em,.5em)$)--($(math.north east)-(2em,.5em)$);\n" + " }\n" + "}\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}"); + "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #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{\\textcyrillic}[1]{\\leavevmode{\\cyrtext #1}}\n"); static docstring const lyxmathsym_def = from_ascii( "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n" @@ -226,6 +275,13 @@ static docstring const papersizepdf_def = from_ascii( "\\pdfpageheight\\paperheight\n" "\\pdfpagewidth\\paperwidth\n"); +static docstring const papersizepdflua_def = from_ascii( + "% Backwards compatibility for LuaTeX < 0.90\n" + "\\@ifundefined{pageheight}{\\let\\pageheight\\pdfpageheight}{}\n" + "\\@ifundefined{pagewidth}{\\let\\pagewidth\\pdfpagewidth}{}\n" + "\\pageheight\\paperheight\n" + "\\pagewidth\\paperwidth\n"); + static docstring const cedilla_def = from_ascii( "\\newcommand{\\docedilla}[2]{\\underaccent{#1\\mathchar'30}{#2}}\n" "\\newcommand{\\cedilla}[1]{\\mathpalette\\docedilla{#1}}\n"); @@ -266,15 +322,68 @@ 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"); + +// split-level fractions +static docstring const xfrac_def = from_ascii( + "\\usepackage{xfrac}\n"); +static docstring const smallLetterFrac_def = from_ascii( + "\\DeclareCollectionInstance{smallLetterFrac}{xfrac}{default}{text}\n" + " {phantom=c, scale-factor=1.0, slash-left-kern=-.05em}\n" + "\\DeclareCollectionInstance{smallLetterFrac}{xfrac}{lmr}{text}\n" + " {slash-symbol-font=ptm, phantom=c, scale-factor=1, slash-left-kern=-.05em}\n" + "\\DeclareCollectionInstance{smallLetterFrac}{xfrac}{lmss}{text}\n" + " {slash-symbol-font=ptm, phantom=c, scale-factor=1, slash-left-kern=-.05em}\n" + "\\DeclareCollectionInstance{smallLetterFrac}{xfrac}{cmr}{text}\n" + " {slash-symbol-font=ptm, phantom=c, scale-factor=1, slash-left-kern=-.05em}\n" + "\\DeclareCollectionInstance{smallLetterFrac}{xfrac}{cmss}{text}\n" + " {slash-symbol-font=ptm, phantom=c, scale-factor=1, slash-left-kern=-.05em}\n" + "\\newcommand{\\smallLetterFrac}[2]{%\n" + " {\\UseCollection{xfrac}{smallLetterFrac}\\sfrac{#1}{#2}}}\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 @@ -313,6 +422,19 @@ static docstring const rtloutputdblcol_def = from_ascii( "}\n" "\\@mparswitchtrue\n"); +static docstring const lyxmintcaption_def = from_ascii( + "\\long\\def\\lyxmintcaption[#1]#2{%\n" + " \\ifx#1t\\vskip\\baselineskip\\fi%\n" + " \\refstepcounter{listing}\\noindent%\n" + " \\addcontentsline{lol}{listing}%\n" + " {\\protect\\numberline{\\thelisting}{\\ignorespaces #2}}%\n" + " \\setbox\\@tempboxa\\hbox{\\listingscaption~\\thelisting: #2}%\n" + " \\ifdim \\wd\\@tempboxa >\\linewidth%\n" + " \\parbox[t]{\\linewidth}{\\unhbox\\@tempboxa}\\else%\n" + " \\hbox to\\linewidth{\\hfil\\box\\@tempboxa\\hfil}\\fi%\n" + " \\ifx#1b\\vskip\\baselineskip\\fi\n" + "}\n"); + ///////////////////////////////////////////////////////////////////// // @@ -322,15 +444,15 @@ static docstring const rtloutputdblcol_def = from_ascii( static docstring const lyxnoun_style = from_ascii( "dfn.lyxnoun {\n" - " font-variant: small-caps;\n" - "}\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"); + " text-decoration: line-through;\n" + "}\n"); ///////////////////////////////////////////////////////////////////// @@ -342,7 +464,8 @@ static docstring const lyxstrikeout_style = from_ascii( LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p, OutputParams const & r) - : buffer_(&b), params_(p), runparams_(r), in_float_(false) + : buffer_(&b), params_(p), runparams_(r), in_float_(false), + in_deleted_inset_(false) {} @@ -361,18 +484,18 @@ LaTeXFeatures::LangPackage LaTeXFeatures::langPackage() const if (local_lp == "none") return LANG_PACK_NONE; - /* If "auto" is selected, we load polyglossia if required, + /* 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 = - isRequired("polyglossia") + params_.useNonTeXFonts && isAvailable("polyglossia") && !isProvided("babel") && this->hasOnlyPolyglossiaLanguages(); - bool const babel_required = + bool const babel_required = !bufferParams().language->babel().empty() || !this->getBabelLanguages().empty(); @@ -425,10 +548,21 @@ void LaTeXFeatures::require(set const & names) } +void LaTeXFeatures::provide(string const & name) +{ + provides_.insert(name); +} + + 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 " @@ -448,9 +582,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 { @@ -458,8 +590,6 @@ void LaTeXFeatures::useLayout(docstring const & layoutname) << to_utf8(layoutname) << "' does not exist in this class" << endl; } - - --level; } @@ -489,29 +619,34 @@ bool LaTeXFeatures::isRequired(string const & name) const bool LaTeXFeatures::isProvided(string const & name) const { + // Currently, this is only features provided by babel languages + // (such as textgreek) + if (provides_.find(name) != provides_.end()) + return true; + if (params_.useNonTeXFonts) return params_.documentClass().provides(name); - bool const ot1 = (params_.font_encoding() == "default" - || params_.font_encoding() == "OT1"); - bool const complete = (params_.fonts_sans == "default") - && (params_.fonts_typewriter == "default"); - bool const nomath = (params_.fonts_math == "default"); + bool const ot1 = (params_.main_font_encoding() == "default" + || params_.main_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_.fonts_roman)).provides(name, ot1, + from_ascii(params_.fontsRoman())).provides(name, ot1, complete, nomath) || theLaTeXFonts().getLaTeXFont( - from_ascii(params_.fonts_sans)).provides(name, ot1, + from_ascii(params_.fontsSans())).provides(name, ot1, complete, nomath) || theLaTeXFonts().getLaTeXFont( - from_ascii(params_.fonts_typewriter)).provides(name, ot1, + from_ascii(params_.fontsTypewriter())).provides(name, ot1, complete, nomath) || theLaTeXFonts().getLaTeXFont( - from_ascii(params_.fonts_math)).provides(name, ot1, + from_ascii(params_.fontsMath())).provides(name, ot1, complete, nomath); } @@ -536,24 +671,62 @@ bool LaTeXFeatures::isAvailable(string const & name) } -void LaTeXFeatures::addPreambleSnippet(string const & preamble) +namespace { + +void addSnippet(std::list & list, TexString ts, bool allow_dupes) +{ + if (allow_dupes || + // test the absense of duplicates, i.e. elements with same str + none_of(list.begin(), list.end(), [&](TexString const & ts2){ + return ts.str == ts2.str; + }) + ) + list.push_back(move(ts)); +} + + +TexString getSnippets(std::list const & list) +{ + otexstringstream snip; + for (TexString const & ts : list) + snip << TexString(ts) << '\n'; + return snip.release(); +} + +} // namespace + + +void LaTeXFeatures::addPreambleSnippet(TexString ts, bool allow_dupes) { - SnippetList::const_iterator begin = preamble_snippets_.begin(); - SnippetList::const_iterator end = preamble_snippets_.end(); - if (find(begin, end, preamble) == end) - preamble_snippets_.push_back(preamble); + addSnippet(preamble_snippets_, move(ts), allow_dupes); +} + + +void LaTeXFeatures::addPreambleSnippet(docstring const & str, bool allow_dupes) +{ + addSnippet(preamble_snippets_, TexString(str), allow_dupes); } void LaTeXFeatures::addCSSSnippet(std::string const & snippet) { - SnippetList::const_iterator begin = css_snippets_.begin(); - SnippetList::const_iterator end = css_snippets_.end(); - if (find(begin, end, snippet) == end) - css_snippets_.push_back(snippet); + addSnippet(css_snippets_, TexString(from_ascii(snippet)), false); +} + + +TexString LaTeXFeatures::getPreambleSnippets() const +{ + return getSnippets(preamble_snippets_); } +docstring LaTeXFeatures::getCSSSnippets() const +{ + return getSnippets(css_snippets_).str; +} + + + void LaTeXFeatures::useFloat(string const & name, bool subfloat) { if (!usedFloats_[name]) @@ -576,6 +749,9 @@ void LaTeXFeatures::useLanguage(Language const * lang) UsedLanguages_.insert(lang); if (!lang->requires().empty()) require(lang->requires()); + // currently only supported for Babel + if (!lang->provides().empty() && useBabel()) + provide(lang->provides()); // CJK languages do not have a babel name. // They use the CJK package if (lang->encoding()->package() == Encoding::CJK) @@ -600,6 +776,10 @@ bool LaTeXFeatures::hasLanguages() 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(); @@ -613,6 +793,10 @@ bool LaTeXFeatures::hasOnlyPolyglossiaLanguages() 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(); @@ -624,9 +808,45 @@ bool LaTeXFeatures::hasPolyglossiaExclusiveLanguages() const } +vector LaTeXFeatures::getPolyglossiaExclusiveLanguages() const +{ + vector result; + // first the main language + if (params_.language->isPolyglossiaExclusive()) + result.push_back(params_.language->display()); + // now the secondary languages + LanguageList::const_iterator const begin = UsedLanguages_.begin(); + for (LanguageList::const_iterator cit = begin; + cit != UsedLanguages_.end(); + ++cit) { + if ((*cit)->isPolyglossiaExclusive()) + result.push_back((*cit)->display()); + } + return result; +} + + +vector LaTeXFeatures::getBabelExclusiveLanguages() const +{ + vector result; + // first the main language + if (params_.language->isBabelExclusive()) + result.push_back(params_.language->display()); + // now the secondary languages + LanguageList::const_iterator const begin = UsedLanguages_.begin(); + for (LanguageList::const_iterator cit = begin; + cit != UsedLanguages_.end(); + ++cit) { + if ((*cit)->isBabelExclusive()) + result.push_back((*cit)->display()); + } + return result; +} + + string LaTeXFeatures::getBabelLanguages() const { - ostringstream languages; + ostringstream langs; bool first = true; LanguageList::const_iterator const begin = UsedLanguages_.begin(); @@ -636,26 +856,27 @@ string LaTeXFeatures::getBabelLanguages() const if ((*cit)->babel().empty()) continue; if (!first) - languages << ','; + langs << ','; else first = false; - languages << (*cit)->babel(); + langs << (*cit)->babel(); } - return languages.str(); + return langs.str(); } -std::map LaTeXFeatures::getPolyglossiaLanguages() const +set LaTeXFeatures::getPolyglossiaLanguages() const { - std::map languages; + set langs; LanguageList::const_iterator const begin = UsedLanguages_.begin(); for (LanguageList::const_iterator cit = begin; cit != UsedLanguages_.end(); ++cit) { - languages[(*cit)->polyglossia()] = (*cit)->polyglossiaOpts(); + // We do not need the variants here + langs.insert((*cit)->polyglossia()); } - return languages; + return langs; } @@ -664,15 +885,48 @@ set LaTeXFeatures::getEncodingSet(string const & doc_encoding) const // This does only find encodings of languages supported by babel, but // that does not matter since we don't have a language with an // encoding supported by inputenc but without babel support. - set encodings; - LanguageList::const_iterator it = UsedLanguages_.begin(); - LanguageList::const_iterator end = UsedLanguages_.end(); - for (; it != end; ++it) - if ((*it)->encoding()->latexName() != doc_encoding && - ((*it)->encoding()->package() == Encoding::inputenc - || (*it)->encoding()->package() == Encoding::japanese)) - encodings.insert((*it)->encoding()->latexName()); - return encodings; + set encs; + for (auto const & lang : UsedLanguages_) + if (lang->encoding()->latexName() != doc_encoding && + (lang->encoding()->package() == Encoding::inputenc + || lang->encoding()->package() == Encoding::japanese)) + encs.insert(lang->encoding()->latexName()); + return encs; +} + + +void LaTeXFeatures::getFontEncodings(vector & encs, bool const onlylangs) const +{ + if (!onlylangs) { + // these must be loaded if glyphs of this script are used + // unless a language providing them is used in the document + if (mustProvide("textgreek") + && find(encs.begin(), encs.end(), "LGR") == encs.end()) + encs.insert(encs.begin(), "LGR"); + if (mustProvide("textcyrillic") + && find(encs.begin(), encs.end(), "T2A") == encs.end()) + encs.insert(encs.begin(), "T2A"); + } + + for (auto const & lang : UsedLanguages_) { + vector extraencs = + getVectorFromString(lang->fontenc(buffer().masterParams())); + for (auto const & extra : extraencs) { + if (extra != "none" && find(encs.begin(), encs.end(), extra) == encs.end()) + encs.insert(encs.begin(), extra); + } + } +} + + +bool LaTeXFeatures::hasRTLLanguage() const +{ + if (params_.language->rightToLeft()) + return true; + for (auto const & lang : UsedLanguages_) + if (lang->rightToLeft()) + return true; + return false; } namespace { @@ -681,6 +935,7 @@ char const * simplefeatures[] = { // note that the package order here will be the same in the LaTeX-output "array", "verbatim", + "cprotect", "longtable", "rotating", "latexsym", @@ -701,16 +956,12 @@ char const * simplefeatures[] = { "fancybox", "calc", "units", - "tipa", - "tipx", - "tone", "framed", "soul", "textcomp", "pmboxdraw", "bbding", "ifsym", - "marvosym", "txfonts", "pxfonts", "mathdesign", @@ -734,7 +985,22 @@ char const * simplefeatures[] = { "multicol", "multirow", "tfrupee", - "shapepar" + "shapepar", + "rsphrase", + "hpstatement", + "algorithm2e", + "sectionbox", + "tcolorbox", + "pdfcomment", + "fixme", + "todonotes", + "forest", + "varwidth", + "footnote", + "tablefootnote", + "afterpage", + "tabularx", + "xltabular" }; char const * bibliofeatures[] = { @@ -746,6 +1012,7 @@ char const * bibliofeatures[] = { "authordate1-4", "babelbib", "bibgerm", + "chapterbib", "chicago", "chscite", "harvard", @@ -757,7 +1024,7 @@ int const nb_bibliofeatures = sizeof(bibliofeatures) / sizeof(char const *); int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *); -} +} // namespace string const LaTeXFeatures::getColorOptions() const @@ -820,6 +1087,22 @@ 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; @@ -830,16 +1113,6 @@ string const LaTeXFeatures::getPackages() const // also unknown packages can be requested. They are silently // swallowed now. We should change this eventually. - // 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)) - packages << "\\PassOptionsToPackage{" << it->second << "}" - << "{" << it->first << "}\n"; - // These are all the 'simple' includes. i.e // packages which we just \usepackage{package} for (int i = 0; i < nb_simplefeatures; ++i) { @@ -850,33 +1123,49 @@ string const LaTeXFeatures::getPackages() const // 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) + // [pdf]lscape is used to rotate longtables + if (mustProvide("lscape")) { + if (runparams_.flavor == OutputParams::LATEX + || runparams_.flavor == OutputParams::DVILUATEX) + packages << "\\usepackage{lscape}\n"; + else + packages << "\\usepackage{pdflscape}\n"; + } + + // 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("extraipa") && !params_.useNonTeXFonts) + packages << "\\usepackage{extraipa}\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_.main_font_encoding() == "default" + || params_.main_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"; - 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") && @@ -935,8 +1224,29 @@ string const LaTeXFeatures::getPackages() const 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"; @@ -956,12 +1266,18 @@ string const LaTeXFeatures::getPackages() const // 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") && !isProvided("natbib-internal")) { + if (mustProvide("natbib") + && !isProvided("natbib-internal") + && !isProvided("biblatex") + && !isProvided("biblatex-natbib") + && !isProvided("jurabib")) { packages << "\\usepackage["; if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL) packages << "numbers"; else packages << "authoryear"; + if (!params_.biblio_opts.empty()) + packages << ',' << params_.biblio_opts; packages << "]{natbib}\n"; } @@ -973,8 +1289,16 @@ string const LaTeXFeatures::getPackages() const } // jurabib -- we need version 0.6 at least. - if (mustProvide("jurabib")) - packages << "\\usepackage{jurabib}[2004/01/25]\n"; + if (mustProvide("jurabib") + && !isProvided("natbib-internal") + && !isProvided("natbib") + && !isProvided("biblatex") + && !isProvided("biblatex-natbib")) { + packages << "\\usepackage"; + if (!params_.biblio_opts.empty()) + packages << '[' << params_.biblio_opts << ']'; + packages << "{jurabib}[2004/01/25]\n"; + } // opcit -- we pass custombst as we output \bibliographystyle ourselves if (mustProvide("opcit")) { @@ -998,11 +1322,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 @@ -1018,44 +1337,38 @@ string const LaTeXFeatures::getPackages() const if (mustProvide("subscript") && !isRequired("fixltx2e")) packages << "\\usepackage{subscript}\n"; - return packages.str(); -} - - -string LaTeXFeatures::getPreambleSnippets() const -{ - ostringstream snip; - SnippetList::const_iterator pit = preamble_snippets_.begin(); - SnippetList::const_iterator pend = preamble_snippets_.end(); - for (; pit != pend; ++pit) - snip << *pit << '\n'; - return snip.str(); -} + // 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"; + } -std::string LaTeXFeatures::getCSSSnippets() const -{ - ostringstream snip; - SnippetList::const_iterator pit = css_snippets_.begin(); - SnippetList::const_iterator pend = css_snippets_.end(); - for (; pit != pend; ++pit) - snip << *pit << '\n'; - return snip.str(); + return packages.str(); } -docstring const LaTeXFeatures::getMacros() const +TexString LaTeXFeatures::getMacros() const { - odocstringstream macros; + otexstringstream macros; if (!preamble_snippets_.empty()) { macros << '\n'; - macros << from_utf8(getPreambleSnippets()); + macros << getPreambleSnippets(); } + if (mustProvide("xetexdashbreakstate")) + macros << "\\XeTeXdashbreakstate 0" << '\n'; + if (mustProvide("papersize")) { - if (runparams_.flavor == OutputParams::LATEX) + if (runparams_.flavor == OutputParams::LATEX + || runparams_.flavor == OutputParams::DVILUATEX) macros << papersizedvi_def << '\n'; + else if (runparams_.flavor == OutputParams::LUATEX) + macros << papersizepdflua_def << '\n'; else macros << papersizepdf_def << '\n'; } @@ -1065,6 +1378,8 @@ docstring const LaTeXFeatures::getMacros() const macros << lyx_hyperref_def << '\n'; else macros << lyx_def << '\n'; + if (runparams_.use_polyglossia && hasRTLLanguage()) + macros << lyx_rtl_def << '\n'; } if (mustProvide("noun")) @@ -1073,22 +1388,46 @@ docstring const LaTeXFeatures::getMacros() const if (mustProvide("lyxarrow")) macros << lyxarrow_def << '\n'; + if (mustProvide("lyxzerowidthspace")) + macros << lyxZWSP_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_.main_font_encoding() == "default") + macros << textgreek_LGR_def; + macros << textgreek_def << '\n'; } - if (!usePolyglossia() && mustProvide("textcyr")) + if (!usePolyglossia() && mustProvide("textcyrillic")) { + // ensure T2A font encoding is set up also if fontenc is not loaded by LyX + if (params_.main_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'; + + // split-level fractions + if (mustProvide("xfrac") || mustProvide("smallLetterFrac")) + macros << xfrac_def << '\n'; + + if (mustProvide("smallLetterFrac")) + macros << smallLetterFrac_def << '\n'; if (mustProvide("lyxmathsym")) macros << lyxmathsym_def << '\n'; @@ -1136,6 +1475,20 @@ docstring const LaTeXFeatures::getMacros() const macros << guillemotleft_def << '\n'; if (mustProvide("guillemotright")) macros << guillemotright_def << '\n'; + if (mustProvide("textquotedbl")) + macros << textquotedbl_def << '\n'; + if (mustProvide("textquotesinglep")) { + if (runparams_.flavor == OutputParams::XETEX) + macros << textquotesinglep_xetex_def << '\n'; + else + macros << textquotesinglep_luatex_def << '\n'; + } + if (mustProvide("textquotedblp")) { + if (runparams_.flavor == OutputParams::XETEX) + macros << textquotedblp_xetex_def << '\n'; + else + macros << textquotedblp_luatex_def << '\n'; + } // Math mode if (mustProvide("binom") && !isRequired("amsmath")) @@ -1173,7 +1526,7 @@ docstring const LaTeXFeatures::getMacros() const macros << changetracking_dvipost_def; if (mustProvide("ct-xcolor-ulem")) { - streamsize const prec = macros.precision(2); + streamsize const prec = macros.os().precision(2); RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext)); macros << "\\providecolor{lyxadded}{rgb}{" @@ -1183,7 +1536,7 @@ docstring const LaTeXFeatures::getMacros() const macros << "\\providecolor{lyxdeleted}{rgb}{" << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n"; - macros.precision(prec); + macros.os().precision(prec); if (isRequired("hyperref")) macros << changetracking_xcolor_ulem_hyperref_def; @@ -1191,25 +1544,29 @@ docstring const LaTeXFeatures::getMacros() const macros << changetracking_xcolor_ulem_def; } + if (mustProvide("ct-tikz-math-sout")) + macros << changetracking_tikz_math_sout_def; + if (mustProvide("ct-none")) macros << changetracking_none_def; if (mustProvide("rtloutputdblcol")) macros << rtloutputdblcol_def; - return macros.str(); + if (mustProvide("lyxmintcaption")) + macros << lyxmintcaption_def; + + return macros.release(); } -string const LaTeXFeatures::getBabelPresettings() const +docstring const LaTeXFeatures::getBabelPresettings() const { - ostringstream tmp; + odocstringstream tmp; - LanguageList::const_iterator it = UsedLanguages_.begin(); - LanguageList::const_iterator end = UsedLanguages_.end(); - for (; it != end; ++it) - if (!(*it)->babel_presettings().empty()) - tmp << (*it)->babel_presettings() << '\n'; + for (Language const * lang : UsedLanguages_) + if (!lang->babel_presettings().empty()) + tmp << lang->babel_presettings() << '\n'; if (!params_.language->babel_presettings().empty()) tmp << params_.language->babel_presettings() << '\n'; @@ -1220,15 +1577,13 @@ string const LaTeXFeatures::getBabelPresettings() const } -string const LaTeXFeatures::getBabelPostsettings() const +docstring const LaTeXFeatures::getBabelPostsettings() const { - ostringstream tmp; + odocstringstream tmp; - LanguageList::const_iterator it = UsedLanguages_.begin(); - LanguageList::const_iterator end = UsedLanguages_.end(); - for (; it != end; ++it) - if (!(*it)->babel_postsettings().empty()) - tmp << (*it)->babel_postsettings() << '\n'; + for (Language const * lang : UsedLanguages_) + if (!lang->babel_postsettings().empty()) + tmp << lang->babel_postsettings() << '\n'; if (!params_.language->babel_postsettings().empty()) tmp << params_.language->babel_postsettings() << '\n'; @@ -1257,8 +1612,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) { @@ -1271,6 +1624,9 @@ string const LaTeXFeatures::loadAMSPackages() const tmp << "\\usepackage{amstext}\n"; } + if (mustProvide("amsthm")) + tmp << "\\usepackage{amsthm}\n"; + if (mustProvide("amssymb") && params_.use_package("amssymb") != BufferParams::package_off) tmp << "\\usepackage{amssymb}\n"; @@ -1290,7 +1646,10 @@ docstring const LaTeXFeatures::getTClassPreamble() const list::const_iterator cit = usedLayouts_.begin(); list::const_iterator end = usedLayouts_.end(); for (; cit != end; ++cit) - tcpreamble << tclass[*cit].preamble(); + // For InPreamble layouts, we output the preamble stuff earlier + // (before the layouts). See Paragraph::Private::validate. + if (!tclass[*cit].inpreamble) + tcpreamble << tclass[*cit].preamble(); cit = usedInsetLayouts_.begin(); end = usedInsetLayouts_.end(); @@ -1399,7 +1758,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; @@ -1411,6 +1771,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 @@ -1424,25 +1802,28 @@ 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); } -} +} // namespace -docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_polyglossia) const +docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, + bool use_polyglossia, bool use_minted) const { DocumentClass const & tclass = params_.documentClass(); // collect preamble snippets in a set to prevent multiple identical @@ -1458,20 +1839,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()) { @@ -1519,24 +1900,32 @@ 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 = !use_minted && + !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)); } } @@ -1584,7 +1973,7 @@ void LaTeXFeatures::showStruct() const { lyxerr << "LyX needs the following commands when LaTeXing:" << "\n***** Packages:" << getPackages() - << "\n***** Macros:" << to_utf8(getMacros()) + << "\n***** Macros:" << to_utf8(getMacros().str) << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble()) << "\n***** done." << endl; } @@ -1608,7 +1997,7 @@ BufferParams const & LaTeXFeatures::bufferParams() const } -void LaTeXFeatures::getFloatDefinitions(odocstream & os) const +void LaTeXFeatures::getFloatDefinitions(otexstream & os) const { FloatList const & floats = params_.documentClass().floats(); @@ -1671,7 +2060,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"; } } @@ -1683,10 +2073,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); @@ -1697,4 +2100,24 @@ void LaTeXFeatures::resolveAlternatives() } +void LaTeXFeatures::expandMultiples() +{ + for (Features::iterator it = features_.begin(); it != features_.end();) { + if (contains(*it, ',')) { + vector const multiples = getVectorFromString(*it, ","); + vector::const_iterator const end = multiples.end(); + vector::const_iterator itm = multiples.begin(); + // Do nothing if any multiple is already required + for (; itm != end; ++itm) { + if (!isRequired(*itm)) + require(*itm); + } + features_.erase(it); + it = features_.begin(); + } else + ++it; + } +} + + } // namespace lyx