[LyX/master] DocBook: fix handling of listings with titles.
Thibaut Cuvelier
tcuvelier at lyx.org
Sun Nov 15 02:33:48 UTC 2020
commit c4bbff8ecbab0d43c1788b4e3c337f703d69ab4b
Author: Thibaut Cuvelier <tcuvelier at lyx.org>
Date: Sun Nov 15 02:49:52 2020 +0100
DocBook: fix handling of listings with titles.
Also implement a code path for inline listings.
---
src/insets/InsetFloat.cpp | 4 ++
src/insets/InsetListings.cpp | 105 ++++++++++++++++++++++++++++++++++++------
2 files changed, 94 insertions(+), 15 deletions(-)
diff --git a/src/insets/InsetFloat.cpp b/src/insets/InsetFloat.cpp
index 92d3ad0..86e3f9b 100644
--- a/src/insets/InsetFloat.cpp
+++ b/src/insets/InsetFloat.cpp
@@ -514,6 +514,8 @@ std::vector<const InsetCollapsible *> findSubfiguresInParagraph(const Paragraph
}
+namespace {
+
const InsetLabel* findLabelInParagraph(const Paragraph &par)
{
for (pos_type pos = 0; pos < par.size(); ++pos) {
@@ -549,6 +551,8 @@ const InsetLabel* findLabelInParagraph(const Paragraph &par)
return nullptr;
}
+} // anonymous namespace
+
const InsetCaption* findCaptionInParagraph(const Paragraph &par)
{
diff --git a/src/insets/InsetListings.cpp b/src/insets/InsetListings.cpp
index 93daab4..cff7bcc 100644
--- a/src/insets/InsetListings.cpp
+++ b/src/insets/InsetListings.cpp
@@ -23,6 +23,7 @@
#include "FuncRequest.h"
#include "FuncStatus.h"
#include "InsetCaption.h"
+#include "InsetLabel.h"
#include "Language.h"
#include "LaTeXFeatures.h"
#include "Lexer.h"
@@ -481,31 +482,99 @@ docstring InsetListings::xhtml(XMLStream & os, OutputParams const & rp) const
}
+namespace {
+
+const InsetLabel* findLabelInParagraph(const Paragraph &par)
+{
+ for (pos_type pos = 0; pos < par.size(); ++pos) {
+ const Inset *inset = par.getInset(pos);
+
+ // Maybe an inset is directly a label, in which case no more work is needed.
+ if (inset && dynamic_cast<const InsetLabel *>(inset))
+ return dynamic_cast<const InsetLabel *>(inset);
+
+ // More likely, the label is hidden in an inset of a paragraph (only if a subtype of InsetText).
+ if (!dynamic_cast<const InsetText *>(inset))
+ continue;
+
+ auto insetAsText = dynamic_cast<const InsetText *>(inset);
+ auto itIn = insetAsText->paragraphs().begin();
+ auto endIn = insetAsText->paragraphs().end();
+ for (; itIn != endIn; ++itIn) {
+ for (pos_type posIn = 0; posIn < itIn->size(); ++posIn) {
+ const Inset *insetIn = itIn->getInset(posIn);
+ if (insetIn && dynamic_cast<const InsetLabel *>(insetIn)) {
+ return dynamic_cast<const InsetLabel *>(insetIn);
+ }
+ }
+ }
+
+ // Obviously, this solution does not scale with more levels of paragraphs-insets, but this should be enough.
+ }
+
+ return nullptr;
+}
+
+} // anonymous namespace
+
+
void InsetListings::docbook(XMLStream & xs, OutputParams const & rp) const
{
InsetLayout const & il = getLayout();
+ bool isInline = params().isInline();
- if (!xs.isLastTagCR())
+ if (!isInline && !xs.isLastTagCR())
xs << xml::CR();
+ // In case of caption, the code must be wrapped, for instance in a figure. Also detect if there is a label.
+ // http://www.sagehill.net/docbookxsl/ProgramListings.html
+ // TODO: parts of this code could be merged with InsetFloat and findLabelInParagraph.
+ InsetCaption const * caption = getCaptionInset();
+ if (caption) {
+ // Find the label in the caption, if any.
+ InsetLabel const * label;
+ auto const end = caption->paragraphs().end();
+ for (auto it = caption->paragraphs().begin(); it != end; ++it) {
+ label = findLabelInParagraph(*it);
+ if (label)
+ break;
+ }
+
+ // Ensure that the label will not be output a second time as an anchor.
+ OutputParams rpNoLabel = rp;
+ if (label)
+ rpNoLabel.docbook_anchors_to_ignore.emplace(label->screenLabel());
+
+ // Prepare the right set of attributes, including the label.
+ docstring attr = from_ascii("type='listing'");
+ if (label)
+ attr += " xml:id=\"" + xml::cleanID(label->screenLabel()) + "\"";
+
+ // Finally, generate the wrapper (including the label).
+ xs << xml::StartTag("figure", attr);
+ xs << xml::CR();
+ xs << xml::StartTag("title");
+ xs << XMLStream::ESCAPE_NONE << getCaptionDocBook(rpNoLabel);
+ xs << xml::EndTag("title");
+ xs << xml::CR();
+ }
+
// Forge the attributes.
- string attrs;
+ std::string attrs;
if (!il.docbookattr().empty())
attrs += " role=\"" + il.docbookattr() + "\"";
- string const lang = params().getParamValue("language");
+ std::string const lang = params().getParamValue("language");
if (!lang.empty())
attrs += " language=\"" + lang + "\"";
- xs << xml::StartTag(il.docbooktag(), attrs);
- xs.startDivision(false);
- // Deal with the caption.
- docstring caption = getCaptionDocBook(rp);
- if (!caption.empty()) {
- xs << xml::StartTag("bridgehead");
- xs << XMLStream::ESCAPE_NONE;
- xs << caption;
- xs << xml::EndTag("bridgehead");
- }
+ // Determine the tag to use. Use the layout-defined value if outside a paragraph.
+ std::string tag = il.docbooktag();
+ if (isInline)
+ tag = "code";
+
+ // Start the listing.
+ xs << xml::StartTag(tag, attrs);
+ xs.startDivision(false);
// Deal with the content of the listing.
OutputParams newrp = rp;
@@ -519,8 +588,14 @@ void InsetListings::docbook(XMLStream & xs, OutputParams const & rp) const
// Done with the listing.
xs.endDivision();
- xs << xml::EndTag(il.docbooktag());
- xs << xml::CR();
+ xs << xml::EndTag(tag);
+ if (!isInline)
+ xs << xml::CR();
+
+ if (caption) {
+ xs << xml::EndTag("figure");
+ xs << xml::CR();
+ }
}
More information about the lyx-cvs
mailing list