From 262e436fc3e8e2a61e729b774b4d501bb7a7c83e Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Thu, 14 Mar 2019 14:24:43 +0100 Subject: [PATCH] Move labels and insets out of moving arguments Fixes: #2154 --- src/OutputParams.cpp | 4 ++-- src/OutputParams.h | 13 +++++++++++++ src/Paragraph.cpp | 3 +++ src/insets/InsetCaption.cpp | 9 +++++++++ src/insets/InsetIndex.cpp | 11 ++++++++++- src/insets/InsetLabel.cpp | 14 ++++++++++++++ src/insets/InsetLabel.h | 2 ++ src/insets/InsetText.cpp | 2 ++ src/output_latex.cpp | 33 ++++++++++++++++++++++++++++++++- 9 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/OutputParams.cpp b/src/OutputParams.cpp index cb9d50c175..36816c2f7f 100644 --- a/src/OutputParams.cpp +++ b/src/OutputParams.cpp @@ -24,8 +24,8 @@ OutputParams::OutputParams(Encoding const * enc) master_language(0), encoding(enc), free_spacing(false), use_babel(false), use_polyglossia(false), use_CJK(false), use_indices(false), use_japanese(false), linelen(0), depth(0), - exportdata(new ExportData), inDisplayMath(false), wasDisplayMath(false), - inComment(false), openbtUnit(false), only_childbibs(false), + exportdata(new ExportData), postpone_fragile_stuff(false), inDisplayMath(false), + wasDisplayMath(false), inComment(false), openbtUnit(false), only_childbibs(false), inTableCell(NO), inFloat(NONFLOAT), inIndexEntry(false), inIPA(false), inDeletedInset(0), changeOfDeletedInset(Change::UNCHANGED), diff --git a/src/OutputParams.h b/src/OutputParams.h index ef7c16d117..5faa68e2e4 100644 --- a/src/OutputParams.h +++ b/src/OutputParams.h @@ -197,6 +197,19 @@ public: */ std::shared_ptr exportdata; + /** Store labels, index entries (etc.) (in \ref post_macro) + * and output them later. This is used in particular to get + * labels and index entries (and potentially other fragile commands) + * outside of moving arguments (bug 2154) + */ + bool postpone_fragile_stuff; + + /** Stuff to be postponed and output after the current macro + * (if \ref postpone_fragile_stuff is true). Used for labels and index + * entries in commands with moving arguments (\\section, \\caption etc.) + */ + mutable docstring post_macro; + /** Whether we are entering a display math inset. * Needed to correctly strike out deleted math in change tracking. */ diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 27aecb5eae..f1fc7bd886 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -2833,6 +2833,9 @@ void Paragraph::latex(BufferParams const & bparams, // such as Note that do not produce any output, so that no // command is ever executed but its opening was recorded. runparams.inulemcmd = rp.inulemcmd; + + // And finally, pass the post_macros upstream + runparams.post_macro = rp.post_macro; } // If we have an open font definition, we have to close it diff --git a/src/insets/InsetCaption.cpp b/src/insets/InsetCaption.cpp index 0ebbcea379..941047f337 100644 --- a/src/insets/InsetCaption.cpp +++ b/src/insets/InsetCaption.cpp @@ -264,7 +264,16 @@ void InsetCaption::latex(otexstream & os, // \caption{...}, later we will make it take advantage // of the one of the caption packages. (Lgb) OutputParams runparams = runparams_in; + // Some fragile commands (labels, index entries) + // are output after the caption (#2154) + runparams.postpone_fragile_stuff = true; InsetText::latex(os, runparams); + if (!runparams.post_macro.empty()) { + // Output the stored fragile commands (labels, indices etc.) + // that need to be output after the caption. + os << runparams.post_macro; + runparams.post_macro.clear(); + } // Backwards compatibility: We always had a linebreak after // the caption (see #8514) os << breakln; diff --git a/src/insets/InsetIndex.cpp b/src/insets/InsetIndex.cpp index 9ac768060f..f3fafce60b 100644 --- a/src/insets/InsetIndex.cpp +++ b/src/insets/InsetIndex.cpp @@ -59,11 +59,13 @@ InsetIndex::InsetIndex(Buffer * buf, InsetIndexParams const & params) {} -void InsetIndex::latex(otexstream & os, OutputParams const & runparams_in) const +void InsetIndex::latex(otexstream & ios, OutputParams const & runparams_in) const { OutputParams runparams(runparams_in); runparams.inIndexEntry = true; + otexstringstream os; + if (buffer().masterBuffer()->params().use_indices && !params_.index.empty() && params_.index != "idx") { os << "\\sindex["; @@ -170,6 +172,13 @@ void InsetIndex::latex(otexstream & os, OutputParams const & runparams_in) const os << "|" << cmd; } os << '}'; + + // In macros with moving arguments, such as \section, + // we store the index and output it after the macro (#2154) + if (runparams_in.postpone_fragile_stuff) + runparams_in.post_macro += os.str(); + else + ios << os.release(); } diff --git a/src/insets/InsetLabel.cpp b/src/insets/InsetLabel.cpp index e325f1ea94..9d6a031c28 100644 --- a/src/insets/InsetLabel.cpp +++ b/src/insets/InsetLabel.cpp @@ -28,6 +28,7 @@ #include "output_xhtml.h" #include "ParIterator.h" #include "sgml.h" +#include "texstream.h" #include "Text.h" #include "TextClass.h" #include "TocBackend.h" @@ -294,6 +295,19 @@ void InsetLabel::doDispatch(Cursor & cur, FuncRequest & cmd) } +void InsetLabel::latex(otexstream & os, OutputParams const & runparams_in) const +{ + OutputParams runparams = runparams_in; + docstring command = getCommand(runparams); + // In macros with moving arguments, such as \section, + // we store the label and output it after the macro (#2154) + if (runparams_in.postpone_fragile_stuff) + runparams_in.post_macro += command; + else + os << command; +} + + int InsetLabel::plaintext(odocstringstream & os, OutputParams const &, size_t) const { diff --git a/src/insets/InsetLabel.h b/src/insets/InsetLabel.h index 92c3380f70..ef4fed9cac 100644 --- a/src/insets/InsetLabel.h +++ b/src/insets/InsetLabel.h @@ -48,6 +48,8 @@ public: /// InsetCode lyxCode() const { return LABEL_CODE; } /// + void latex(otexstream & os, OutputParams const & runparams_in) const; + /// int plaintext(odocstringstream & ods, OutputParams const & op, size_t max_length = INT_MAX) const; /// diff --git a/src/insets/InsetText.cpp b/src/insets/InsetText.cpp index 8f2ba0c5ff..85da8dd4ec 100644 --- a/src/insets/InsetText.cpp +++ b/src/insets/InsetText.cpp @@ -509,6 +509,8 @@ void InsetText::latex(otexstream & os, OutputParams const & runparams) const // Output the contents of the inset latexParagraphs(buffer(), text_, os, rp); runparams.encoding = rp.encoding; + // Pass the post_macros upstream + runparams.post_macro = rp.post_macro; if (!il.rightdelim().empty()) os << il.rightdelim(); diff --git a/src/output_latex.cpp b/src/output_latex.cpp index d515ef4886..8ccb9f5eb6 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -777,6 +777,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 << '{'; @@ -861,6 +866,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 << '{'; } @@ -1071,8 +1081,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); @@ -1092,6 +1108,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()); @@ -1246,6 +1268,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()); @@ -1324,6 +1352,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