X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Foutput_latex.cpp;h=517ef13d22d17da0ca5927c680a7c37d6349b7ba;hb=1e519d1115f41f71c253cb9e2fbb7803e9a583a9;hp=23068de13186e7875d982c04aec59bee510e380c;hpb=fc0ab1283c7153c3c1a09febd0951ec45b4126bb;p=lyx.git diff --git a/src/output_latex.cpp b/src/output_latex.cpp index 23068de131..517ef13d22 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -12,6 +12,7 @@ #include "output_latex.h" +#include "BiblioInfo.h" #include "Buffer.h" #include "BufferParams.h" #include "Encoding.h" @@ -304,8 +305,11 @@ static TeXEnvironmentData prepareEnvironment(Buffer const & buf, // in multilingual environments, the CJK tags have to be nested properly data.cjk_nested = false; - if (data.par_language->encoding()->package() == Encoding::CJK && - state->open_encoding_ != CJK && pit->isMultiLingual(bparams)) { + if (!bparams.useNonTeXFonts + && (bparams.inputenc == "auto-legacy" + || bparams.inputenc == "auto-legacy-plain") + && data.par_language->encoding()->package() == Encoding::CJK + && state->open_encoding_ != CJK && pit->isMultiLingual(bparams)) { if (prev_par_language->encoding()->package() == Encoding::CJK) { os << "\\begin{CJK}{" << from_ascii(data.par_language->encoding()->latexName()) @@ -697,6 +701,11 @@ void parStartCommand(Paragraph const & par, otexstream & os, os << " "; } break; + case LATEX_ENVIRONMENT: + if (runparams.for_search) { + os << "\\latexenvironment{" << style.latexname() << "}{"; + } + break; case LATEX_BIB_ENVIRONMENT: // ignore this, the inset will write itself break; @@ -772,6 +781,11 @@ void TeXOnePar(Buffer const & buf, if (style.pass_thru) { Font const outerfont = text.outerFont(pit); parStartCommand(par, os, runparams, style); + if (style.isCommand() && style.needprotect) + // Due to the moving argument, some fragile + // commands (labels, index entries) + // are output after this command (#2154) + runparams.postpone_fragile_stuff = true; if (intitle_command) os << '{'; @@ -856,6 +870,11 @@ void TeXOnePar(Buffer const & buf, // (see #10849); thus open the command here. if (intitle_command) { parStartCommand(par, os, runparams, style); + if (style.isCommand() && style.needprotect) + // Due to the moving argument, some fragile + // commands (labels, index entries) + // are output after this command (#2154) + runparams.postpone_fragile_stuff = true; os << '{'; } @@ -964,11 +983,12 @@ void TeXOnePar(Buffer const & buf, } } - // Switch file encoding if necessary; no need to do this for "default" + // Switch file encoding if necessary; no need to do this for "auto-legacy-plain" // encoding, since this only affects the position of the outputted // \inputencoding command; the encoding switch will occur when necessary - if (bparams.inputenc == "auto" + if (bparams.inputenc == "auto-legacy" && !runparams.isFullUnicode() // Xe/LuaTeX use one document-wide encoding (see also switchEncoding()) + && runparams.encoding->package() != Encoding::japanese && runparams.encoding->package() != Encoding::none) { // Look ahead for future encoding changes. // We try to output them at the beginning of the paragraph, @@ -1031,6 +1051,8 @@ void TeXOnePar(Buffer const & buf, } runparams.moving_arg |= style.needprotect; + if (style.needmboxprotect) + ++runparams.inulemcmd; Encoding const * const prev_encoding = runparams.encoding; bool const useSetSpace = bparams.documentClass().provides("SetSpace"); @@ -1064,8 +1086,14 @@ void TeXOnePar(Buffer const & buf, // For InTitle commands, we already started the command before // the language switch - if (!intitle_command) + if (!intitle_command) { parStartCommand(par, os, runparams, style); + if (style.isCommand() && style.needprotect) + // Due to the moving argument, some fragile + // commands (labels, index entries) + // are output after this command (#2154) + runparams.postpone_fragile_stuff = true; + } Font const outerfont = text.outerFont(pit); @@ -1085,6 +1113,12 @@ void TeXOnePar(Buffer const & buf, os << '}'; if (!style.postcommandargs().empty()) latexArgInsets(par, os, runparams, style.postcommandargs(), "post:"); + if (!runparams.post_macro.empty()) { + // Output the stored fragile commands (labels, indices etc.) + // that need to be output after the command with moving argument. + os << runparams.post_macro; + runparams.post_macro.clear(); + } if (runparams.encoding != prev_encoding) { runparams.encoding = prev_encoding; os << setEncoding(prev_encoding->iconvName()); @@ -1107,7 +1141,7 @@ void TeXOnePar(Buffer const & buf, pending_newline = true; break; case LATEX_ENVIRONMENT: { - // if its the last paragraph of the current environment + // if it's the last paragraph of the current environment // skip it otherwise fall through if (nextpar && ((nextpar->layout() != par.layout() @@ -1161,7 +1195,7 @@ void TeXOnePar(Buffer const & buf, if (localswitch_needed || (intitle_command && using_begin_end) || closing_rtl_ltr_environment - || ((runparams.isLastPar || close_lang_switch) + || (((runparams.isLastPar && !runparams.inbranch) || close_lang_switch) && (par_lang != outer_lang || (using_begin_end && style.isEnvironment() && par_lang != nextpar_lang)))) { @@ -1239,6 +1273,12 @@ void TeXOnePar(Buffer const & buf, os << '}'; if (!style.postcommandargs().empty()) latexArgInsets(par, os, runparams, style.postcommandargs(), "post:"); + if (!runparams.post_macro.empty()) { + // Output the stored fragile commands (labels, indices etc.) + // that need to be output after the command with moving argument. + os << runparams.post_macro; + runparams.post_macro.clear(); + } if (runparams.encoding != prev_encoding) { runparams.encoding = prev_encoding; os << setEncoding(prev_encoding->iconvName()); @@ -1260,7 +1300,8 @@ void TeXOnePar(Buffer const & buf, // if this is a CJK-paragraph and the next isn't, close CJK // also if the next paragraph is a multilingual environment (because of nesting) if (nextpar - && (state->open_encoding_ == CJK && bparams.encoding().iconvName() != "UTF-8") + && (state->open_encoding_ == CJK && bparams.encoding().iconvName() != "UTF-8" + && bparams.encoding().package() != Encoding::CJK ) && (nextpar_language->encoding()->package() != Encoding::CJK || (nextpar->layout().isEnvironment() && nextpar->isMultiLingual(bparams))) // inbetween environments, CJK has to be closed later (nesting!) @@ -1300,13 +1341,13 @@ void TeXOnePar(Buffer const & buf, } } - // If this is the last paragraph, and a local_font was set upon entering - // the inset, and we're using "auto" or "default" encoding, and not - // compiling with XeTeX or LuaTeX, the encoding - // should be set back to that local_font's encoding. + // Information about local language is stored as a font feature. + // If this is the last paragraph of the inset and a local_font was set upon entering + // and we are mixing encodings ("auto-legacy" or "auto-legacy-plain" and no XeTeX or LuaTeX), + // ensure the encoding is set back to the default encoding of the local language. if (runparams.isLastPar && runparams_in.local_font != 0 && runparams_in.encoding != runparams_in.local_font->language()->encoding() - && (bparams.inputenc == "auto" || bparams.inputenc == "default") + && (bparams.inputenc == "auto-legacy" || bparams.inputenc == "auto-legacy-plain") && !runparams.isFullUnicode() ) { runparams_in.encoding = runparams_in.local_font->language()->encoding(); @@ -1316,6 +1357,9 @@ void TeXOnePar(Buffer const & buf, else runparams_in.encoding = runparams.encoding; + // Also pass the post_macros upstream + runparams_in.post_macro = runparams.post_macro; + // we don't need a newline for the last paragraph!!! // Note from JMarc: we will re-add a \n explicitly in @@ -1354,7 +1398,7 @@ void TeXOnePar(Buffer const & buf, && nextpar->getAlign() == par.getAlign()) || (!next_layout.isEnvironment() && nextpar->getDepth() > par.getDepth() - && nextpar->getAlign() == par.getAlign()) + && nextpar->getAlign() == next_layout.align) || (!style.isEnvironment() && next_layout.latextype == LATEX_ENVIRONMENT && nextpar->getDepth() < par.getDepth()) @@ -1396,7 +1440,8 @@ void latexParagraphs(Buffer const & buf, if (multibib_child && mparams.useBiblatex()) os << "\\newrefsection"; - else if (multibib_child && mparams.useBibtopic()) { + else if (multibib_child && mparams.useBibtopic() + && !buf.masterBibInfo().empty()) { os << "\\begin{btUnit}\n"; runparams.openbtUnit = true; } @@ -1409,11 +1454,8 @@ void latexParagraphs(Buffer const & buf, if (maintext && !is_child && !bparams.useNonTeXFonts && (bparams.encoding().package() == Encoding::CJK || (bparams.encoding().name() == "utf8" - && bparams.language->encoding()->package() == Encoding::CJK) - // FIXME: should test if any language requires CJK - // && LaTeXFeatures::mustProvide("CJK")) - // error: cannot call member function ‘bool lyx::LaTeXFeatures::mustProvide(const string&) const’ without object - )) { + && runparams.use_CJK)) + ) { docstring const cjkenc = bparams.encoding().iconvName() == "UTF-8" ? from_ascii("UTF8") : from_ascii(bparams.encoding().latexName()); os << "\\begin{CJK}{" << cjkenc @@ -1509,7 +1551,8 @@ void latexParagraphs(Buffer const & buf, && layout.latexname() == bparams.multibib) { if (runparams.openbtUnit) os << "\\end{btUnit}\n"; - if (!bparams.useBiblatex()) { + if (!bparams.useBiblatex() + && !buf.masterBibInfo().empty()) { os << '\n' << "\\begin{btUnit}\n"; runparams.openbtUnit = true; } @@ -1568,14 +1611,23 @@ void latexParagraphs(Buffer const & buf, state->open_encoding_ = none; } // Likewise for polyglossia or when using begin/end commands + // or after an active branch inset with a language switch + Language const * const outer_language = (runparams.local_font != 0) + ? runparams.local_font->language() : bparams.language; + string const & prev_lang = runparams.use_polyglossia + ? getPolyglossiaEnvName(outer_language) + : outer_language->babel(); string const & cur_lang = openLanguageName(state); - if (maintext && !is_child && !cur_lang.empty()) { + if (((runparams.inbranch && langOpenedAtThisLevel(state) && prev_lang != cur_lang) + || (maintext && !is_child)) && !cur_lang.empty()) { os << from_utf8(subst(lang_end_command, "$$lang", cur_lang)) << '\n'; if (using_begin_end) popLanguageName(); + } else if (runparams.inbranch && !using_begin_end && prev_lang != cur_lang) { + os << subst(lang_begin_command, "$$lang", prev_lang) << '\n'; } // reset inherited encoding @@ -1591,61 +1643,56 @@ void latexParagraphs(Buffer const & buf, } } - +// Switch the input encoding for some part(s) of the document. pair switchEncoding(odocstream & os, BufferParams const & bparams, OutputParams const & runparams, Encoding const & newEnc, bool force, bool noswitchmacro) { - // XeTeX/LuaTeX use only one encoding per document: - // * with useNonTeXFonts: "utf8plain", - // * with XeTeX and TeX fonts: "ascii" (inputenc fails), - // * with LuaTeX and TeX fonts: only one encoding accepted by luainputenc. - if (runparams.isFullUnicode() || newEnc.name() == "inherit") + // Never switch encoding with non-TeX fonts (always "utf8plain"), + // with LuaTeX and TeX fonts (only one encoding accepted by luainputenc), + // or if we're in a moving argument or inherit the outer encoding. + if (bparams.useNonTeXFonts + || runparams.flavor == OutputParams::LUATEX + || runparams.flavor == OutputParams::DVILUATEX + || newEnc.name() == "inherit") + return make_pair(false, 0); + + // Only switch for auto-selected legacy encodings (inputenc setting + // "auto-legacy" or "auto-legacy-plain"). + // The "listings" environment can force a switch also with other + // encoding settings (it does not support variable width encodings + // (utf8, jis, ...) under 8-bit latex engines). + if (!force && ((bparams.inputenc != "auto-legacy" && bparams.inputenc != "auto-legacy-plain") + || runparams.moving_arg)) return make_pair(false, 0); Encoding const & oldEnc = *runparams.encoding; - bool moving_arg = runparams.moving_arg; - // If we switch from/to CJK, we need to switch anyway, despite custom inputenc, - // except if we use CJKutf8 or explicitely set inputenc to a CJK encoding - bool const from_to_cjk = - ((oldEnc.package() == Encoding::CJK && newEnc.package() != Encoding::CJK) - || (oldEnc.package() != Encoding::CJK && newEnc.package() == Encoding::CJK)) - && (bparams.encoding().name() != "utf8-cjk" && bparams.encoding().name() != "utf8") - && bparams.encoding().package() != Encoding::CJK; - if (!force && !from_to_cjk - && ((bparams.inputenc != "auto" && bparams.inputenc != "default") || moving_arg)) - return make_pair(false, 0); - - // Do nothing if the encoding is unchanged. - if (oldEnc.name() == newEnc.name()) + // Do not switch, if the encoding is unchanged or switching is not supported. + if (oldEnc.name() == newEnc.name() + || oldEnc.package() == Encoding::japanese + || oldEnc.package() == Encoding::none + || newEnc.package() == Encoding::none + || runparams.for_search) return make_pair(false, 0); - // FIXME We ignore encoding switches from/to encodings that do // neither support the inputenc package nor the CJK package here. - // This does of course only work in special cases (e.g. switch from - // tis620-0 to latin1, but the text in latin1 contains ASCII only), - // but it is the best we can do - // - // 2019-01-08 Possibly no longer required since tis620-0 is supported - // by inputenc (but check special encodings "utf8-plain" and "default"). - if (oldEnc.package() == Encoding::none || newEnc.package() == Encoding::none) - return make_pair(false, 0); + // This may fail for characters not supported by "unicodesymbols" + // or for non-ASCII characters in "listings" + // but it is the best we can do. - // change encoding (not required with UTF8) - if (bparams.encoding().iconvName() != "UTF-8") { - LYXERR(Debug::LATEX, "Changing LaTeX encoding from " - << oldEnc.name() << " to " << newEnc.name()); - os << setEncoding(newEnc.iconvName()); - if (bparams.inputenc == "default") - return make_pair(true, 0); - } + // change encoding + LYXERR(Debug::LATEX, "Changing LaTeX encoding from " + << oldEnc.name() << " to " << newEnc.name()); + os << setEncoding(newEnc.iconvName()); + if (bparams.inputenc == "auto-legacy-plain") + return make_pair(true, 0); docstring const inputenc_arg(from_ascii(newEnc.latexName())); OutputState * state = getOutputState(); switch (newEnc.package()) { case Encoding::none: case Encoding::japanese: - // shouldn't ever reach here, see above + // shouldn't ever reach here (see above) but avoids warning. return make_pair(true, 0); case Encoding::inputenc: { int count = inputenc_arg.length(); @@ -1670,8 +1717,7 @@ pair switchEncoding(odocstream & os, BufferParams const & bparams, count += 7; state->open_encoding_ = inputenc; } - // with the japanese option, inputenc is omitted. - if (runparams.use_japanese || noswitchmacro) + if (noswitchmacro) return make_pair(true, count); os << "\\inputencoding{" << inputenc_arg << '}'; return make_pair(true, count + 16); @@ -1688,9 +1734,8 @@ pair switchEncoding(odocstream & os, BufferParams const & bparams, os << "\\egroup"; count += 7; } - docstring const cjkenc = (bparams.encoding().iconvName() == "UTF-8" - ? from_ascii("UTF8") : from_ascii(newEnc.latexName())); - os << "\\begin{CJK}{" << cjkenc << "}{" + os << "\\begin{CJK}{" + << from_ascii(newEnc.latexName()) << "}{" << from_ascii(bparams.fonts_cjk) << "}"; state->open_encoding_ = CJK; return make_pair(true, count + 15);