[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