From 49e3f8e830a7c8a15f4d9f73e4dab78e93b24bf7 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 23 Dec 2017 13:25:13 +0100 Subject: [PATCH] Fix switch of language and line spacing in InTitle commands. Fixes: #9332, #10849 --- src/Paragraph.cpp | 8 +++- src/Spacing.cpp | 22 +++++++++++ src/Spacing.h | 3 ++ src/output_latex.cpp | 88 ++++++++++++++++++++++++++++++++------------ 4 files changed, 96 insertions(+), 25 deletions(-) diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index a6c72c310e..4f55280d35 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -2424,7 +2424,9 @@ void Paragraph::latex(BufferParams const & bparams, // if the paragraph is empty, the loop will not be entered at all if (empty()) { - if (style.isCommand()) { + // For InTitle commands, we have already opened a group + // in output_latex::TeXOnePar. + if (style.isCommand() && style.intitle) { os << '{'; ++column; } @@ -2462,7 +2464,9 @@ void Paragraph::latex(BufferParams const & bparams, os << "}] "; column +=3; } - if (style.isCommand()) { + // For InTitle commands, we have already opened a group + // in output_latex::TeXOnePar. + if (style.isCommand() && !style.intitle) { os << '{'; ++column; } diff --git a/src/Spacing.cpp b/src/Spacing.cpp index cd5816e600..9ac8345ab4 100644 --- a/src/Spacing.cpp +++ b/src/Spacing.cpp @@ -99,6 +99,18 @@ string envName(Spacing::Space space, bool useSetSpace) return useSetSpace ? name : support::ascii_lowercase(name); } +string cmdName(Spacing::Space space, bool useSetSpace) +{ + static char const * const cmd_names[] + = { "SingleSpacing", "OnehalfSpacing", "DoubleSpacing", "SetStretch", ""}; + string const name = cmd_names[space]; + + if (useSetSpace && name == "SetStretch") + return "setSpacing"; + + return useSetSpace ? name : support::ascii_lowercase(name); +} + } // namespace string const Spacing::writeEnvirBegin(bool useSetSpace) const @@ -118,6 +130,16 @@ string const Spacing::writeEnvirEnd(bool useSetSpace) const } +string const Spacing::writeCmd(bool useSetSpace) const +{ + string const name = cmdName(space, useSetSpace); + if (space == Other) + return "\\" + name + "{" + getValueAsString() + '}'; + else + return name.empty() ? string() : "\\" + name + "{}"; +} + + string const Spacing::writePreamble(bool useSetSpace) const { string preamble; diff --git a/src/Spacing.h b/src/Spacing.h index 274cfc20f2..7311f792b5 100644 --- a/src/Spacing.h +++ b/src/Spacing.h @@ -62,6 +62,9 @@ public: std::string const writeEnvirEnd(bool useSetSpace) const; /// useSetSpace is true when using the variant supported by /// the memoir class. + std::string const writeCmd(bool useSetSpace) const; + /// useSetSpace is true when using the variant supported by + /// the memoir class. std::string const writePreamble(bool useSetSpace) const; private: diff --git a/src/output_latex.cpp b/src/output_latex.cpp index 1431bbb321..5bb21cc2ac 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -812,6 +812,14 @@ 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. + bool const intitle_command = style.intitle && style.latextype == LATEX_COMMAND; + 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()); @@ -975,19 +983,34 @@ 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 @@ -1000,13 +1023,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()); + } } } @@ -1039,12 +1065,13 @@ void TeXOnePar(Buffer const & buf, // 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) @@ -1060,9 +1087,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" @@ -1074,7 +1102,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() @@ -1145,6 +1174,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);