From 875f7d42e2eb6b9b4cef3c29213b12f85f9756bb Mon Sep 17 00:00:00 2001 From: Thibaut Cuvelier Date: Sun, 2 Aug 2020 04:03:17 +0200 Subject: [PATCH] DocBook: avoid generating empty paragraphs instead of new pages. As this required to first generate the paragraph before outputting it if necessary, tests like XMLStream::isTagOpen no more worked properly. This also refactors table handling to get rid of that case (and make code easier to read). --- .../docbook/bibliography_precooked_aastex.xml | 5 - src/OutputParams.cpp | 2 +- src/OutputParams.h | 3 + src/insets/InsetFloat.cpp | 197 ++++++++++-------- src/insets/InsetTabular.cpp | 6 +- src/output_docbook.cpp | 24 ++- 6 files changed, 133 insertions(+), 104 deletions(-) diff --git a/autotests/export/docbook/bibliography_precooked_aastex.xml b/autotests/export/docbook/bibliography_precooked_aastex.xml index bc1016804d..89b1714bfe 100644 --- a/autotests/export/docbook/bibliography_precooked_aastex.xml +++ b/autotests/export/docbook/bibliography_precooked_aastex.xml @@ -967,11 +967,8 @@ v(p,\lambda)_{\pm} & = & \pm\lambda(E\mp\lambda|{\textbf{p}}|)^{1/2}\chi Peterson, C. J. 1976, , 81, 617 Spitzer, L. 1985, Dynamics of Star Clusters, J. Goodman and P. Hut, Dordrecht: Reidel, 109 - - - @@ -1209,8 +1206,6 @@ v(p,\lambda)_{\pm} & = & \pm\lambda(E\mp\lambda|{\textbf{p}}|)^{1/2}\chi We can also attach a long-ish paragraph of explanatory material to a table. Use \tablerefs to append a list of references. The following references were from a different table: I've patched them in here to show how they look, but don't take them too seriously—I certainly have not.(1) Barbuy, Spite, & Spite 1985; (2) Bond 1980; (3) Carbon et al. 1987; (4) Hobbs & Duncan 1987; (5) Gilroy et al. 1988: (6) Gratton & Ortolani 1986; (7) Gratton & Sneden 1987; (8) Gratton & Sneden (1988); (9) Gratton & Sneden 1991; (10) Kraft et al. 1982; (11) LCL, or Laird, 1990; (12) Leep & Wallerstein 1981; (13) Luck & Bond 1981; (14) Luck & Bond 1985; (15) Magain 1987; (16) Magain 1989; (17) Peterson 1981; (18) Peterson, Kurucz, & Carney 1990; (19) RMB; (20) Schuster & Nissen 1988; (21) Schuster & Nissen 1989b; (22) Spite et al. 1984; (23) Spite & Spite 1986; (24) Hobbs & Thorburn 1991; (25) Hobbs et al. 1991; (26) Olsen 1983.
Terribly relevant tabular information.
Star
- - \ No newline at end of file diff --git a/src/OutputParams.cpp b/src/OutputParams.cpp index 465282c494..a7e0fd5601 100644 --- a/src/OutputParams.cpp +++ b/src/OutputParams.cpp @@ -35,7 +35,7 @@ OutputParams::OutputParams(Encoding const * enc) html_disable_captions(false), html_in_par(false), html_make_pars(true), docbook_in_par(false), docbook_make_pars(true), docbook_force_pars(false), docbook_anchors_to_ignore(std::set()), docbook_in_float(false), - docbook_in_listing(false), for_toc(false), for_tooltip(false), + docbook_in_listing(false), docbook_in_table(false), for_toc(false), for_tooltip(false), for_search(false), for_preview(false), includeall(false) { // Note: in PreviewLoader::Impl::dumpPreamble diff --git a/src/OutputParams.h b/src/OutputParams.h index c2e85dc39f..31a705982e 100644 --- a/src/OutputParams.h +++ b/src/OutputParams.h @@ -369,6 +369,9 @@ public: /// Is the current context a listing? bool docbook_in_listing; + /// Is the current context a table? + bool docbook_in_table; + /// Are we generating this material for inclusion in a TOC-like entity? bool for_toc; diff --git a/src/insets/InsetFloat.cpp b/src/insets/InsetFloat.cpp index 1cd614e5ce..b0a48f2b31 100644 --- a/src/insets/InsetFloat.cpp +++ b/src/insets/InsetFloat.cpp @@ -563,6 +563,109 @@ const InsetCaption* findCaptionInParagraph(const Paragraph &par) } +void docbookSubfigures(XMLStream & xs, OutputParams const & runparams, const InsetCaption * caption, + const InsetLabel * label, std::vector & subfigures) +{ + // Ensure there is no label output, it is supposed to be handled as xml:id. + OutputParams rpNoLabel = runparams; + if (label) + rpNoLabel.docbook_anchors_to_ignore.emplace(label->screenLabel()); + + // First, open the formal group. + docstring attr = docstring(); + if (label) + attr += "xml:id=\"" + xml::cleanID(label->screenLabel()) + "\""; + + xs.startDivision(false); + xs << xml::StartTag("formalgroup", attr); + xs << xml::CR(); + + xs << xml::StartTag("title", attr); + if (caption) { + caption->getCaptionAsDocBook(xs, rpNoLabel); + } else { + xs << "No caption"; + // No caption has been detected, but this tag is required for the document to be valid DocBook. + } + xs << xml::EndTag("title"); + xs << xml::CR(); + + // Deal with each subfigure individually. This should also deal with their caption and their label. + // This should be a recursive call to InsetFloat. + for (const InsetBox *subfigure: subfigures) { + // If there is no InsetFloat in the paragraphs, output a warning. + bool foundInsetFloat = false; + for (const auto & it : subfigure->paragraphs()) { + for (pos_type posIn = 0; posIn < it.size(); ++posIn) { + const Inset *inset = it.getInset(posIn); + if (inset && dynamic_cast(inset)) { + foundInsetFloat = true; + break; + } + } + + if (foundInsetFloat) + break; + } + + if (!foundInsetFloat) + xs << XMLStream::ESCAPE_NONE << "Error: no float found in the box. " + "To use subfigures in DocBook, elements must be wrapped in a float " + "inset and have a title/caption."; + // TODO: could also output a table, that would ensure that the document is correct and *displays* correctly (but without the right semantics), instead of just an error. + + // Finally, recurse. + subfigure->docbook(xs, runparams); + } + + // Every subfigure is done: close the formal group. + xs << xml::EndTag("formalgroup"); + xs << xml::CR(); + xs.endDivision(); +} + + +void docbookNoSubfigures(XMLStream & xs, OutputParams const & runparams, const InsetCaption * caption, + const InsetLabel * label, Floating const & ftype, const InsetFloat * thisFloat) +{ + string const &titleTag = ftype.docbookCaption(); + + // Ensure there is no label output, it is supposed to be handled as xml:id. + OutputParams rpNoLabel = runparams; + if (label) + rpNoLabel.docbook_anchors_to_ignore.emplace(label->screenLabel()); + + // Ensure the float does not output its caption, as it is handled here (DocBook mandates a specific place for + // captions, they cannot appear at the end of the float, albeit LyX is happy with that). + OutputParams rpNoTitle = runparams; + rpNoTitle.docbook_in_float = true; + if (ftype.floattype() == "table") + rpNoTitle.docbook_in_table = true; + + // Organisation: <contents without title/> </float>. + docstring attr = docstring(); + if (label) + attr += "xml:id=\"" + xml::cleanID(label->screenLabel()) + "\""; + if (!ftype.docbookAttr().empty()) { + if (!attr.empty()) + attr += " "; + attr += from_utf8(ftype.docbookAttr()); + } + + xs << xml::StartTag(ftype.docbookTag(caption != nullptr), attr); + xs << xml::CR(); + if (caption != nullptr) { + xs << xml::StartTag(titleTag); + caption->getCaptionAsDocBook(xs, rpNoLabel); + xs << xml::EndTag(titleTag); + xs << xml::CR(); + } + thisFloat->InsetText::docbook(xs, rpNoTitle); + xs << xml::EndTag(ftype.docbookTag(caption != nullptr)); + xs << xml::CR(); +} + + void InsetFloat::docbook(XMLStream & xs, OutputParams const & runparams) const { // Determine whether the float has a title or not. For this, iterate through the paragraphs and look @@ -589,96 +692,12 @@ void InsetFloat::docbook(XMLStream & xs, OutputParams const & runparams) const // Gather a few things from global environment that are shared between all following cases. FloatList const &floats = buffer().params().documentClass().floats(); Floating const &ftype = floats.getType(params_.type); - string const &titleTag = ftype.docbookCaption(); - // Ensure there is no label output, it is supposed to be handled as xml:id. - OutputParams rpNoLabel = runparams; - if (label) - rpNoLabel.docbook_anchors_to_ignore.emplace(label->screenLabel()); - - // Ensure the float does not output its caption, as it is handled here (DocBook mandates a specific place for - // captions, they cannot appear at the end of the float, albeit LyX is happy with that). - OutputParams rpNoTitle = runparams; - rpNoTitle.docbook_in_float = true; - - // Deal with subfigures. - if (!subfigures.empty()) { - // First, open the formal group. - docstring attr = docstring(); - if (label) - attr += "xml:id=\"" + xml::cleanID(label->screenLabel()) + "\""; - - xs.startDivision(false); - xs << xml::StartTag("formalgroup", attr); - xs << xml::CR(); - - xs << xml::StartTag("title", attr); - if (caption) { - caption->getCaptionAsDocBook(xs, rpNoLabel); - } else { - xs << "No caption"; - // No caption has been detected, but this tag is required for the document to be valid DocBook. - } - xs << xml::EndTag("title"); - xs << xml::CR(); - - // Deal with each subfigure individually. This should also deal with their caption and their label. - // This should be a recursive call to InsetFloat. - for (const InsetBox *subfigure: subfigures) { - // If there is no InsetFloat in the paragraphs, output a warning. - bool foundInsetFloat = false; - for (auto it = subfigure->paragraphs().begin(); it != subfigure->paragraphs().end(); ++it) { - for (pos_type posIn = 0; posIn < it->size(); ++posIn) { - const Inset *inset = it->getInset(posIn); - if (inset && dynamic_cast<const InsetFloat*>(inset)) { - foundInsetFloat = true; - break; - } - } - - if (foundInsetFloat) - break; - } - - if (!foundInsetFloat) - xs << XMLStream::ESCAPE_NONE << "Error: no float found in the box. " - "To use subfigures in DocBook, elements must be wrapped in a float " - "inset and have a title/caption."; - // TODO: could also output a table, that would ensure that the document is correct and *displays* correctly (but without the right semantics), instead of just an error. - - // Finally, recurse. - subfigure->docbook(xs, runparams); - } - - // Every subfigure is done: close the formal group. - xs << xml::EndTag("formalgroup"); - xs << xml::CR(); - xs.endDivision(); - } - - // Here, ensured not to have subfigures. - - // Organisation: <float> <title if any/> <contents without title/> </float> - docstring attr = docstring(); - if (label) - attr += "xml:id=\"" + xml::cleanID(label->screenLabel()) + "\""; - if (!ftype.docbookAttr().empty()) { - if (!attr.empty()) - attr += " "; - attr += from_utf8(ftype.docbookAttr()); - } - - xs << xml::StartTag(ftype.docbookTag(caption != nullptr), attr); - xs << xml::CR(); - if (caption != nullptr) { - xs << xml::StartTag(titleTag); - caption->getCaptionAsDocBook(xs, rpNoLabel); - xs << xml::EndTag(titleTag); - xs << xml::CR(); - } - InsetText::docbook(xs, rpNoTitle); - xs << xml::EndTag(ftype.docbookTag(caption != nullptr)); - xs << xml::CR(); + // Switch on subfigures. + if (!subfigures.empty()) + docbookSubfigures(xs, runparams, caption, label, subfigures); + else + docbookNoSubfigures(xs, runparams, caption, label, ftype, this); } diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index 87988afa70..b449ab392e 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -3658,8 +3658,8 @@ void Tabular::docbook(XMLStream & xs, OutputParams const & runparams) const docstring ret; // Some tables are inline. Likely limitation: cannot output a table within a table; is that really a limitation? - bool hasTableStarted = xs.isTagOpen(xml::StartTag("informaltable")) || xs.isTagOpen(xml::StartTag("table")); - if (!hasTableStarted) { + if (!runparams.docbook_in_table) { // Check on the *outer* set of parameters, so that the table can be closed + // properly at the end of this function. xs << xml::StartTag("informaltable"); xs << xml::CR(); } @@ -3742,7 +3742,7 @@ void Tabular::docbook(XMLStream & xs, OutputParams const & runparams) const xs << xml::CR(); // If this method started the table tag, also make it close it. - if (!hasTableStarted) { + if (!runparams.docbook_in_table) { xs << xml::EndTag("informaltable"); xs << xml::CR(); } diff --git a/src/output_docbook.cpp b/src/output_docbook.cpp index 94aac878bd..5e15edcee9 100644 --- a/src/output_docbook.cpp +++ b/src/output_docbook.cpp @@ -463,14 +463,26 @@ ParagraphList::const_iterator makeParagraphs( ((open_par && (!runparams.docbook_in_par || nextpar != pend)) || (!open_par && runparams.docbook_in_par && par == pbegin && nextpar != pend)); - if (open_par) - openParTag(xs, lay); + // Determine if this paragraph has some real content. Things like new pages are not caught + // by Paragraph::empty(), even though they do not generate anything useful in DocBook. + odocstringstream os2; + XMLStream xs2(os2); + par->simpleDocBookOnePar(buf, xs2, runparams, text.outerFont(distance(begin, par)), open_par, close_par, 0); - par->simpleDocBookOnePar(buf, xs, runparams, text.outerFont(distance(begin, par)), open_par, close_par, 0); + docstring cleaned = os2.str(); + static const lyx::regex reg("[ \\r\\n]*"); + cleaned = from_utf8(lyx::regex_replace(to_utf8(cleaned), reg, string(""))); - if (close_par) { - closeTag(xs, lay); - xs << xml::CR(); + if (!cleaned.empty()) { + if (open_par) + openParTag(xs, lay); + + xs << XMLStream::ESCAPE_NONE << os2.str(); + + if (close_par) { + closeTag(xs, lay); + xs << xml::CR(); + } } } return pend;