]> git.lyx.org Git - lyx.git/blobdiff - src/output_latex.cpp
de.po
[lyx.git] / src / output_latex.cpp
index 370b1c308971ecef1955197576f613d806ca14ae..517ef13d22d17da0ca5927c680a7c37d6349b7ba 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "output_latex.h"
 
+#include "BiblioInfo.h"
 #include "Buffer.h"
 #include "BufferParams.h"
 #include "Encoding.h"
@@ -304,14 +305,14 @@ 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) {
-                       docstring const cjkenc = (bparams.encoding().name() == "utf8-cjk"
-                                                 && LaTeXFeatures::isAvailable("CJKutf8")) ?
-                                                       from_ascii("UTF8")
-                                                     : from_ascii(data.par_language->encoding()->latexName());
-                       os << "\\begin{CJK}{" << cjkenc
+                       os << "\\begin{CJK}{"
+                          << from_ascii(data.par_language->encoding()->latexName())
                           << "}{" << from_ascii(bparams.fonts_cjk) << "}%\n";
                }
                state->open_encoding_ = CJK;
@@ -530,6 +531,10 @@ void getArgInsets(otexstream & os, OutputParams const & runparams, Layout::LaTeX
                        }
                }
        }
+       if (runparams.for_search) {
+               // Mark end of arguments for findadv() only
+               os << "\\endarguments{}";
+       }
 }
 
 
@@ -696,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;
@@ -771,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 << '{';
 
@@ -855,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 << '{';
        }
 
@@ -963,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,
@@ -999,11 +1020,8 @@ void TeXOnePar(Buffer const & buf,
                        // context (nesting issue).
                        if (par_language->encoding()->package() == Encoding::CJK
                                && state->open_encoding_ != CJK && state->cjk_inherited_ == 0) {
-                               docstring const cjkenc = (bparams.encoding().name() == "utf8-cjk"
-                                                         && LaTeXFeatures::isAvailable("CJKutf8")) ?
-                                                               from_ascii("UTF8")
-                                                             : from_ascii(par_language->encoding()->latexName());
-                               os << "\\begin{CJK}{" << cjkenc
+                               os << "\\begin{CJK}{"
+                                  << from_ascii(par_language->encoding()->latexName())
                                   << "}{" << from_ascii(bparams.fonts_cjk) << "}%\n";
                                state->open_encoding_ = CJK;
                        }
@@ -1033,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");
@@ -1066,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);
 
@@ -1087,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());
@@ -1109,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()
@@ -1163,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)))) {
@@ -1241,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());
@@ -1262,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!)
@@ -1302,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();
@@ -1318,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
@@ -1356,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())
@@ -1398,23 +1440,22 @@ 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;
        }
 
        // Open a CJK environment at the beginning of the main buffer
-       // (but not in child documents or documents using system fonts)
-       // if the document's language is a CJK language (with some exceptions)
-       // or the document encoding is utf8-cjk:
+       // if the document's main encoding requires the CJK package
+       // or the document encoding is utf8 and the CJK package is required
+       // (but not in child documents or documents using system fonts):
        OutputState * state = getOutputState();
        if (maintext && !is_child && !bparams.useNonTeXFonts
-           && ((bparams.language->encoding()->package() == Encoding::CJK
-                        && (bparams.encoding().iconvName() != "UTF-8"
-                                || bparams.encoding().name() == "utf8-cjk"
-                                || bparams.encoding().name() == "utf8" ))
-                       || (bparams.encoding().name() == "utf8-cjk"
-                               && LaTeXFeatures::isAvailable("CJKutf8")))) {
+           && (bparams.encoding().package() == Encoding::CJK
+                       || (bparams.encoding().name() == "utf8"
+                               && runparams.use_CJK))
+          ) {
                docstring const cjkenc = bparams.encoding().iconvName() == "UTF-8"
                                                                 ? from_ascii("UTF8") : from_ascii(bparams.encoding().latexName());
                os << "\\begin{CJK}{" << cjkenc
@@ -1510,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;
                        }
@@ -1569,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
@@ -1592,61 +1643,56 @@ void latexParagraphs(Buffer const & buf,
        }
 }
 
-
+// Switch the input encoding for some part(s) of the document.
 pair<bool, int> 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
-       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")
-                       || !LaTeXFeatures::isAvailable("CJKutf8"));
-       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();
@@ -1671,8 +1717,7 @@ pair<bool, int> 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);
@@ -1689,10 +1734,8 @@ pair<bool, int> switchEncoding(odocstream & os, BufferParams const & bparams,
                                os << "\\egroup";
                                count += 7;
                        }
-                       docstring const cjkenc = (bparams.encoding().iconvName() == "UTF-8"
-                                                                         && LaTeXFeatures::isAvailable("CJKutf8"))
-                                                                         ? 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);