]> git.lyx.org Git - features.git/blobdiff - src/output_latex.cpp
Add basic support for cprotect
[features.git] / src / output_latex.cpp
index 4ef1d456243f87ad140c8973b6ac299210a6b299..f8da22ca5c598b5901bc875892420220e6b68389 100644 (file)
@@ -142,11 +142,16 @@ string const getPolyglossiaEnvName(Language const * lang)
 
 
 string const getPolyglossiaBegin(string const & lang_begin_command,
-                                string const & lang, string const & opts)
+                                string const & lang, string const & opts,
+                                bool const localswitch = false)
 {
        string result;
-       if (!lang.empty())
-               result = subst(lang_begin_command, "$$lang", lang);
+       if (!lang.empty()) {
+               // we need to revert the upcasing done in getPolyglossiaEnvName()
+               // in case we have a local polyglossia command (\textarabic).
+               string language = localswitch ? ascii_lowercase(lang) : lang;
+               result = subst(lang_begin_command, "$$lang", language);
+       }
        string options = opts.empty() ?
                    string() : "[" + opts + "]";
        result = subst(result, "$$opts", options);
@@ -363,12 +368,12 @@ void TeXEnvironment(Buffer const & buf, Text const & text,
                    pit_type & pit, otexstream & os)
 {
        ParagraphList const & paragraphs = text.paragraphs();
-       ParagraphList::const_iterator par = paragraphs.constIterator(pit);
+       ParagraphList::const_iterator ipar = paragraphs.constIterator(pit);
        LYXERR(Debug::LATEX, "TeXEnvironment for paragraph " << pit);
 
-       Layout const & current_layout = par->layout();
-       depth_type const current_depth = par->params().depth();
-       Length const & current_left_indent = par->params().leftIndent();
+       Layout const & current_layout = ipar->layout();
+       depth_type const current_depth = ipar->params().depth();
+       Length const & current_left_indent = ipar->params().leftIndent();
 
        // This is for debugging purpose at the end.
        pit_type const par_begin = pit;
@@ -436,10 +441,8 @@ void getArgInsets(otexstream & os, OutputParams const & runparams, Layout::LaTeX
 
        // Default and preset args are always output, so if they require
        // other arguments, consider this.
-       Layout::LaTeXArgMap::const_iterator lit = latexargs.begin();
-       Layout::LaTeXArgMap::const_iterator const lend = latexargs.end();
-       for (; lit != lend; ++lit) {
-               Layout::latexarg arg = (*lit).second;
+       for (auto const & larg : latexargs) {
+               Layout::latexarg const & arg = larg.second;
                if ((!arg.presetarg.empty() || !arg.defaultarg.empty()) && !arg.requires.empty()) {
                                vector<string> req = getVectorFromString(arg.requires);
                                required.insert(required.end(), req.begin(), req.end());
@@ -532,6 +535,14 @@ void popLanguageName()
 }
 
 
+string const & openLanguageName()
+{
+       OutputState * state = getOutputState();
+
+       return openLanguageName(state);
+}
+
+
 namespace {
 
 void addArgInsets(Paragraph const & par, string const & prefix,
@@ -643,6 +654,8 @@ void parStartCommand(Paragraph const & par, otexstream & os,
 {
        switch (style.latextype) {
        case LATEX_COMMAND:
+               if (par.needsCProtection())
+                       os << "\\cprotect";
                os << '\\' << from_ascii(style.latexname());
 
                // Command arguments
@@ -675,7 +688,8 @@ void TeXOnePar(Buffer const & buf,
               otexstream & os,
               OutputParams const & runparams_in,
               string const & everypar,
-              int start_pos, int end_pos)
+              int start_pos, int end_pos,
+              bool const force)
 {
        BufferParams const & bparams = runparams_in.is_child
                ? buf.masterParams() : buf.params();
@@ -686,7 +700,7 @@ void TeXOnePar(Buffer const & buf,
        Layout const & style = text.inset().forcePlainLayout() ?
                bparams.documentClass().plainLayout() : par.layout();
 
-       if (style.inpreamble)
+       if (style.inpreamble && !force)
                return;
 
        LYXERR(Debug::LATEX, "TeXOnePar for paragraph " << pit << " ptr " << &par << " '"
@@ -720,18 +734,22 @@ void TeXOnePar(Buffer const & buf,
                                os << '\n';
                }
 
-               par.latex(bparams, outerfont, os, runparams, start_pos, end_pos);
+               par.latex(bparams, outerfont, os, runparams, start_pos, end_pos, force);
                return;
        }
 
        Paragraph const * nextpar = runparams.isLastPar
                ? 0 : &paragraphs.at(pit + 1);
 
+       bool const intitle_command = style.intitle && style.latextype == LATEX_COMMAND;
+
        if (style.pass_thru) {
                Font const outerfont = text.outerFont(pit);
                parStartCommand(par, os, runparams, style);
+               if (intitle_command)
+                       os << '{';
 
-               par.latex(bparams, outerfont, os, runparams, start_pos, end_pos);
+               par.latex(bparams, outerfont, os, runparams, start_pos, end_pos, force);
 
                // I did not create a parEndCommand for this minuscule
                // task because in the other user of parStartCommand
@@ -804,6 +822,13 @@ void TeXOnePar(Buffer const & buf,
        bool const using_begin_end = use_polyglossia ||
                                        !lang_end_command.empty();
 
+       // For InTitle commands, we need to switch the language inside the command
+       // (see #10849); thus open the command here.
+       if (intitle_command) {
+               parStartCommand(par, os, runparams, style);
+               os << '{';
+       }
+
        // In some insets (such as Arguments), we cannot use \selectlanguage
        bool const localswitch = text.inset().forceLocalFontSwitch()
                        || (using_begin_end && text.inset().forcePlainLayout());
@@ -882,10 +907,12 @@ void TeXOnePar(Buffer const & buf,
                        }
                        // With CJK, the CJK tag has to be closed first (see below)
                        if (runparams.encoding->package() != Encoding::CJK
-                           && par_lang != openLanguageName(state)
+                           && (par_lang != openLanguageName(state) || localswitch)
                            && !par_lang.empty()) {
                                string bc = use_polyglossia ?
-                                         getPolyglossiaBegin(lang_begin_command, par_lang, par_language->polyglossiaOpts())
+                                         getPolyglossiaBegin(lang_begin_command, par_lang,
+                                                             par_language->polyglossiaOpts(),
+                                                             localswitch)
                                          : subst(lang_begin_command, "$$lang", par_lang);
                                os << bc;
                                os << lang_command_termination;
@@ -944,11 +971,13 @@ void TeXOnePar(Buffer const & buf,
                                if (runparams.encoding->package() == Encoding::CJK
                                    && par_lang != openLanguageName(state)
                                    && !par_lang.empty()) {
-                                       os << from_ascii(subst(
-                                               lang_begin_command,
-                                               "$$lang",
-                                               par_lang))
-                                       << lang_command_termination;
+                                       string bc = use_polyglossia ?
+                                                   getPolyglossiaBegin(lang_begin_command, par_lang,
+                                                                       par_language->polyglossiaOpts(),
+                                                                       localswitch)
+                                                   : subst(lang_begin_command, "$$lang", par_lang);
+                                       os << bc
+                                          << lang_command_termination;
                                        if (using_begin_end)
                                                pushLanguageName(par_lang, localswitch);
                                }
@@ -967,24 +996,39 @@ void TeXOnePar(Buffer const & buf,
                        os << "\n\\appendix\n";
                }
 
-               if (!par.params().spacing().isDefault()
-                       && (pit == 0 || !priorpar->hasSameLayout(par)))
-               {
-                       os << from_ascii(par.params().spacing().writeEnvirBegin(useSetSpace))
-                           << '\n';
-               }
+               // InTitle commands must use switches (not environments)
+               // inside the commands (see #9332)
+               if (style.intitle) {
+                       if (!par.params().spacing().isDefault())
+                       {
+                               if (runparams.moving_arg)
+                                       os << "\\protect";
+                               os << from_ascii(par.params().spacing().writeCmd(useSetSpace));
+                       }
+               } else {
+                       if (!par.params().spacing().isDefault()
+                               && (pit == 0 || !priorpar->hasSameLayout(par)))
+                       {
+                               os << from_ascii(par.params().spacing().writeEnvirBegin(useSetSpace))
+                                   << '\n';
+                       }
 
-               if (style.isCommand()) {
-                       os << '\n';
+                       if (style.isCommand()) {
+                               os << '\n';
+                       }
                }
        }
 
-       parStartCommand(par, os, runparams, style);
+       // For InTitle commands, we already started the command before
+       // the language switch
+       if (!intitle_command)
+               parStartCommand(par, os, runparams, style);
+
        Font const outerfont = text.outerFont(pit);
 
        // FIXME UNICODE
        os << from_utf8(everypar);
-       par.latex(bparams, outerfont, os, runparams, start_pos, end_pos);
+       par.latex(bparams, outerfont, os, runparams, start_pos, end_pos, force);
 
        Font const font = par.empty()
                 ? par.getLayoutFont(bparams, outerfont)
@@ -992,13 +1036,16 @@ void TeXOnePar(Buffer const & buf,
 
        bool const is_command = style.isCommand();
 
-       if (is_command) {
-               os << '}';
-               if (!style.postcommandargs().empty())
-                       latexArgInsets(par, os, runparams, style.postcommandargs(), "post:");
-               if (runparams.encoding != prev_encoding) {
-                       runparams.encoding = prev_encoding;
-                       os << setEncoding(prev_encoding->iconvName());
+       // InTitle commands need to be closed after the language has been closed.
+       if (!intitle_command) {
+               if (is_command) {
+                       os << '}';
+                       if (!style.postcommandargs().empty())
+                               latexArgInsets(par, os, runparams, style.postcommandargs(), "post:");
+                       if (runparams.encoding != prev_encoding) {
+                               runparams.encoding = prev_encoding;
+                               os << setEncoding(prev_encoding->iconvName());
+                       }
                }
        }
 
@@ -1028,15 +1075,16 @@ void TeXOnePar(Buffer const & buf,
                        break;
                }
        }
-
-       // fall through possible
+       // possible
+       // fall through
        default:
-               // we don't need it for the last paragraph!!!
-               if (nextpar)
+               // we don't need it for the last paragraph and in InTitle commands!!!
+               if (nextpar && !intitle_command)
                        pending_newline = true;
        }
 
-       if (par.allowParagraphCustomization()) {
+       // InTitle commands use switches (not environments) for space settings
+       if (par.allowParagraphCustomization() && !style.intitle) {
                if (!par.params().spacing().isDefault()
                        && (runparams.isLastPar || !nextpar->hasSameLayout(par))) {
                        if (pending_newline)
@@ -1052,9 +1100,10 @@ void TeXOnePar(Buffer const & buf,
                }
        }
 
-       // Closing the language is needed for the last paragraph; it is also
-       // needed if we're within an \L or \R that we may have opened above (not
-       // necessarily in this paragraph) and are about to close.
+       // Closing the language is needed for the last paragraph in a given language
+       // as well as for any InTitleCommand (since these set the language locally);
+       // it is also needed if we're within an \L or \R that we may have opened above
+       // (not necessarily in this paragraph) and are about to close.
        bool closing_rtl_ltr_environment = !using_begin_end
                // not for ArabTeX
                && (par_language->lang() != "arabic_arabtex"
@@ -1066,7 +1115,8 @@ void TeXOnePar(Buffer const & buf,
                &&((nextpar && par_lang != nextpar_lang)
                   || (runparams.isLastPar && par_lang != outer_lang));
 
-       if (closing_rtl_ltr_environment
+       if ((intitle_command && using_begin_end)
+           || closing_rtl_ltr_environment
            || ((runparams.isLastPar || close_lang_switch)
                && (par_lang != outer_lang || (using_begin_end
                                                && style.isEnvironment()
@@ -1094,7 +1144,8 @@ void TeXOnePar(Buffer const & buf,
                                    && current_lang != openLanguageName(state)) {
                                        string bc = use_polyglossia ?
                                                    getPolyglossiaBegin(lang_begin_command, current_lang,
-                                                                       current_language->polyglossiaOpts())
+                                                                       current_language->polyglossiaOpts(),
+                                                                       localswitch)
                                                  : subst(lang_begin_command, "$$lang", current_lang);
                                        os << bc;
                                        pending_newline = !localswitch;
@@ -1137,6 +1188,19 @@ void TeXOnePar(Buffer const & buf,
        if (closing_rtl_ltr_environment)
                os << "}";
 
+       // InTitle commands need to be closed after the language has been closed.
+       if (intitle_command) {
+               if (is_command) {
+                       os << '}';
+                       if (!style.postcommandargs().empty())
+                               latexArgInsets(par, os, runparams, style.postcommandargs(), "post:");
+                       if (runparams.encoding != prev_encoding) {
+                               runparams.encoding = prev_encoding;
+                               os << setEncoding(prev_encoding->iconvName());
+                       }
+               }
+       }
+
        bool const last_was_separator =
                par.size() > 0 && par.isEnvSeparator(par.size() - 1);
 
@@ -1480,7 +1544,7 @@ pair<bool, int> switchEncoding(odocstream & os, BufferParams const & bparams,
        // * 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())
+       if (runparams.isFullUnicode() || newEnc.name() == "inherit")
                return make_pair(false, 0);
 
        Encoding const & oldEnc = *runparams.encoding;