[LyX/master] DocBook: add layout parameters to control the special case and argument positioning.

Thibaut Cuvelier tcuvelier at lyx.org
Sun Nov 29 21:24:16 UTC 2020


commit 59acb375d1f44f59726b50343c6bdf96f54206b3
Author: Thibaut Cuvelier <tcuvelier at lyx.org>
Date:   Sat Nov 28 22:43:00 2020 +0100

    DocBook: add layout parameters to control the special case and argument positioning.
    
    Only for flex insets.
    
    Also add similar checks in InsetText to avoid bibliographies in paragraphs.
---
 lib/scripts/layout2layout.py |   13 ++++++++++-
 src/Layout.h                 |    1 +
 src/OutputParams.h           |    4 +++
 src/Paragraph.cpp            |    1 +
 src/TextClass.cpp            |    2 +-
 src/insets/InsetArgument.cpp |    5 ++++
 src/insets/InsetArgument.h   |    4 +++
 src/insets/InsetLayout.cpp   |   13 ++++++++++++
 src/insets/InsetLayout.h     |    8 +++++++
 src/insets/InsetText.cpp     |   45 ++++++++++++++++++++++++++++++++++++++++-
 src/output_docbook.cpp       |   36 ++++++++++++++++++++++++++++++++-
 11 files changed, 126 insertions(+), 6 deletions(-)

diff --git a/lib/scripts/layout2layout.py b/lib/scripts/layout2layout.py
index 29159b0..b2393ea 100644
--- a/lib/scripts/layout2layout.py
+++ b/lib/scripts/layout2layout.py
@@ -11,7 +11,7 @@
 # This script will update a .layout file to current format
 
 # The latest layout format is also defined in src/TextClass.cpp
-currentFormat = 87
+currentFormat = 88
 
 
 # Incremented to format 4, 6 April 2007, lasgouttes
@@ -296,7 +296,10 @@ currentFormat = 87
 # Incremented to format 86, 20 October 2020 by tcuvelier
 # New tag DocBookSection.
 
-# Incremeted to format 87, 2 November 2020 by rkh
+# Incremented to format 87, 2 November 2020 by rkh
+
+# Incremented to format 88, 28 November 2020 by tcuvelier
+# New tag DocBookNotInPara.
 
 # Do not forget to document format change in Customization
 # Manual (section "Declaring a new text class").
@@ -358,6 +361,7 @@ def concatenate_label(old, new):
     else:
         return b'"' + old + new + b'"'
 
+
 # appends a string to a list unless it's already there
 def addstring(s, l):
     if l.count(s) > 0:
@@ -547,6 +551,11 @@ def convert(lines, end_format):
                 i += 1
             continue
 
+        if 87 <= format <= 88:
+            # nothing to do.
+            i += 1
+            continue
+
         if format == 86:
             if lines[i].lstrip().lower().startswith(b"stepmastercounter"):
                 pattern = re.compile(b"stepmastercounter", re.IGNORECASE)
diff --git a/src/Layout.h b/src/Layout.h
index cb8f537..dfb5afe 100644
--- a/src/Layout.h
+++ b/src/Layout.h
@@ -115,6 +115,7 @@ public:
 		docstring docbooktag;
 		docstring docbooktagtype;
 		docstring docbookattr;
+		bool docbookargumentbeforemaintag = false;
 	};
 	///
 	typedef std::map<std::string, latexarg> LaTeXArgMap;
diff --git a/src/OutputParams.h b/src/OutputParams.h
index 7e0a4b2..1cd16d2 100644
--- a/src/OutputParams.h
+++ b/src/OutputParams.h
@@ -26,6 +26,7 @@ class Encoding;
 class ExportData;
 class Font;
 class Language;
+class InsetArgument;
 
 class OutputParams {
 public:
@@ -382,6 +383,9 @@ public:
 	/// Should wrappers be ignored? Mostly useful to avoid generation of <abstract>.
 	bool docbook_ignore_wrapper = false;
 
+	/// Some parameters are output before the rest of the paragraph, they should not be generated a second time.
+	std::set<InsetArgument const *> docbook_prepended_arguments = {};
+
 	/// Are we generating this material for inclusion in a TOC-like entity?
 	bool for_toc = false;
 
diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp
index aa6bd30..1e92259 100644
--- a/src/Paragraph.cpp
+++ b/src/Paragraph.cpp
@@ -865,6 +865,7 @@ int Paragraph::eraseChars(pos_type start, pos_type end, bool trackChanges)
 	return end - i;
 }
 
+
 // Handle combining characters
 int Paragraph::Private::latexSurrogatePair(BufferParams const & bparams,
 		otexstream & os, char_type c, char_type next,
diff --git a/src/TextClass.cpp b/src/TextClass.cpp
index cd87cca..a58ae6d 100644
--- a/src/TextClass.cpp
+++ b/src/TextClass.cpp
@@ -59,7 +59,7 @@ namespace lyx {
 // You should also run the development/tools/updatelayouts.py script,
 // to update the format of all of our layout files.
 //
-int const LAYOUT_FORMAT = 87; // rkh: master --> parent for counters
+int const LAYOUT_FORMAT = 88; // tcuvelier: add DocBookNotInPara
 
 
 // Layout format for the current lyx file format. Controls which format is
diff --git a/src/insets/InsetArgument.cpp b/src/insets/InsetArgument.cpp
index 8f1d762..2ae80ca 100644
--- a/src/insets/InsetArgument.cpp
+++ b/src/insets/InsetArgument.cpp
@@ -126,6 +126,7 @@ void InsetArgument::updateBuffer(ParIterator const & it, UpdateType utype, bool
 		docbooktag_ = (*lait).second.docbooktag;
 		docbooktagtype_ = (*lait).second.docbooktagtype;
 		docbookattr_ = (*lait).second.docbookattr;
+		docbookargumentbeforemaintag_ = (*lait).second.docbookargumentbeforemaintag;
 		pass_thru_local_ = false;
 		if (lait->second.is_toc_caption) {
 			is_toc_caption_ = true;
@@ -312,6 +313,10 @@ InsetLayout::InsetDecoration InsetArgument::decoration() const
 
 
 void InsetArgument::docbook(XMLStream & xs, OutputParams const & rp) const {
+	// Ignore arguments that have already been output.
+	if (rp.docbook_prepended_arguments.find(this) != rp.docbook_prepended_arguments.end())
+		return;
+
 	if (docbooktag_ != from_ascii("NONE") && docbooktag_ != from_ascii("IGNORE")) {
 		// TODO: implement docbooktagtype_.
 		xs << xml::StartTag(docbooktag_, docbookattr_);
diff --git a/src/insets/InsetArgument.h b/src/insets/InsetArgument.h
index d5d54a6..1c63e5c 100644
--- a/src/insets/InsetArgument.h
+++ b/src/insets/InsetArgument.h
@@ -39,6 +39,8 @@ public:
 
 	std::string name() const { return name_; }
 
+	bool docbookargumentbeforemaintag() const { return docbookargumentbeforemaintag_; }
+
 	/// \name Public functions inherited from Inset class
 	//@{
 	///
@@ -131,6 +133,8 @@ private:
 	docstring docbooktagtype_;
 	/// DocBook attributes.
 	docstring docbookattr_;
+	///
+	bool docbookargumentbeforemaintag_ = false;
 
 protected:
 	/// \name Protected functions inherited from Inset class
diff --git a/src/insets/InsetLayout.cpp b/src/insets/InsetLayout.cpp
index 62030d0..5b5308d 100644
--- a/src/insets/InsetLayout.cpp
+++ b/src/insets/InsetLayout.cpp
@@ -95,6 +95,8 @@ bool InsetLayout::read(Lexer & lex, TextClass const & tclass,
 		IL_DOCBOOKTAGTYPE,
 		IL_DOCBOOKSECTION,
 		IL_DOCBOOKININFO,
+		IL_DOCBOOKARGUMENTBEFOREMAINTAG,
+		IL_DOCBOOKNOTINPARA,
 		IL_DOCBOOKWRAPPERTAG,
 		IL_DOCBOOKWRAPPERTAGTYPE,
 		IL_DOCBOOKWRAPPERATTR,
@@ -148,6 +150,7 @@ bool InsetLayout::read(Lexer & lex, TextClass const & tclass,
 		{ "custompars", IL_CUSTOMPARS },
 		{ "decoration", IL_DECORATION },
 		{ "display", IL_DISPLAY },
+		{ "docbookargumentbeforemaintag", IL_DOCBOOKARGUMENTBEFOREMAINTAG },
 		{ "docbookattr", IL_DOCBOOKATTR },
 		{ "docbookininfo", IL_DOCBOOKININFO },
 		{ "docbookitemattr", IL_DOCBOOKITEMATTR },
@@ -156,6 +159,7 @@ bool InsetLayout::read(Lexer & lex, TextClass const & tclass,
 		{ "docbookitemwrapperattr", IL_DOCBOOKITEMWRAPPERATTR },
 		{ "docbookitemwrappertag", IL_DOCBOOKITEMWRAPPERTAG },
 		{ "docbookitemwrappertagtype", IL_DOCBOOKITEMWRAPPERTAGTYPE },
+		{ "docbooknotinpara", IL_DOCBOOKNOTINPARA },
 		{ "docbooksection", IL_DOCBOOKSECTION },
 		{ "docbooktag", IL_DOCBOOKTAG },
 		{ "docbooktagtype", IL_DOCBOOKTAGTYPE },
@@ -514,6 +518,12 @@ bool InsetLayout::read(Lexer & lex, TextClass const & tclass,
 		case IL_DOCBOOKININFO:
 			lex >> docbookininfo_;
 			break;
+		case IL_DOCBOOKARGUMENTBEFOREMAINTAG:
+			lex >> docbookargumentbeforemaintag_;
+			break;
+		case IL_DOCBOOKNOTINPARA:
+			lex >> docbooknotinpara_;
+			break;
 		case IL_DOCBOOKSECTION:
 			lex >> docbooksection_;
 			break;
@@ -819,6 +829,9 @@ void InsetLayout::readArgument(Lexer & lex)
 		} else if (tok == "docbooktagtype") {
 			lex.next();
 			arg.docbooktagtype = lex.getDocString();
+		} else if (tok == "docbookargumentbeforemaintag") {
+			lex.next();
+			arg.docbookargumentbeforemaintag = lex.getBool();
 		} else {
 			lex.printError("Unknown tag");
 			error = true;
diff --git a/src/insets/InsetLayout.h b/src/insets/InsetLayout.h
index 09abe71..88143d5 100644
--- a/src/insets/InsetLayout.h
+++ b/src/insets/InsetLayout.h
@@ -158,6 +158,10 @@ public:
 	///
 	bool docbooksection() const { return docbooksection_; }
 	///
+	bool docbooknotinpara() const { return docbooknotinpara_; }
+	///
+	bool docbookargumentbeforemaintag() const { return docbookargumentbeforemaintag_; }
+	///
 	std::string docbookwrappertag() const { return docbookwrappertag_; }
 	///
 	std::string docbookwrappertagtype() const;
@@ -311,6 +315,10 @@ private:
 	///
 	mutable std::string docbookininfo_;
 	///
+	bool docbooknotinpara_ = false;
+	///
+	bool docbookargumentbeforemaintag_ = false;
+	///
 	bool docbooksection_ = false;
 	///
 	std::string docbookwrappertag_;
diff --git a/src/insets/InsetText.cpp b/src/insets/InsetText.cpp
index 2c757a9..bf1fe62 100644
--- a/src/insets/InsetText.cpp
+++ b/src/insets/InsetText.cpp
@@ -621,8 +621,35 @@ void InsetText::docbook(XMLStream & xs, OutputParams const & rp, XHTMLOptions op
 	if (!rp.docbook_generate_info && il.docbookininfo() != "never")
 		return;
 
+	// In some cases, the input parameters must be overridden for outer tags.
+	bool writeOuterTag = opts & WriteOuterTag;
+	if (writeOuterTag) {
+		// For each paragraph, if there are only Bibitems and the corresponding text, don't write the outer tags.
+		bool allBibitems = std::all_of(text().paragraphs().begin(), text().paragraphs().end(), [](Paragraph const & par) {
+			auto nInsets = std::distance(par.insetList().begin(), par.insetList().end());
+			auto parSize = (size_t) par.size();
+			return nInsets == 1 && parSize > 1 && par.insetList().begin()->inset->lyxCode() == BIBITEM_CODE;
+		});
+		writeOuterTag = !allBibitems;
+	}
+
+	// Detect arguments that should be output before the paragraph.
+	// Don't reuse runparams.docbook_prepended_arguments, as the same object is used in InsetArgument to determine
+	// whether the inset should be output or not, whatever the context (i.e. position with respect to the wrapper).
+	std::set<InsetArgument const *> prependedArguments;
+	for (auto const & par : paragraphs()) {
+		for (pos_type i = 0; i < par.size(); ++i) {
+			if (par.getInset(i) && par.getInset(i)->lyxCode() == ARG_CODE) {
+				InsetArgument const *arg = par.getInset(i)->asInsetArgument();
+				if (arg->docbookargumentbeforemaintag())
+					prependedArguments.insert(par.getInset(i)->asInsetArgument());
+			}
+		}
+	}
+
 	// Start outputting this inset.
-	if (opts & WriteOuterTag) {
+	// - First, wrapper around the inset and its main tag.
+	if (writeOuterTag) {
 		if (!il.docbookwrappertag().empty() && il.docbookwrappertag() != "NONE" && il.docbookwrappertag() != "IGNORE")
 			xml::openTag(xs, il.docbookwrappertag(), il.docbookwrapperattr(), il.docbookwrappertagtype());
 
@@ -634,7 +661,19 @@ void InsetText::docbook(XMLStream & xs, OutputParams const & rp, XHTMLOptions op
 				attrs += from_ascii(" xlink:href=\"") + text_.asString() + from_ascii("\"");
 			xml::openTag(xs, il.docbooktag(), attrs, il.docbooktagtype());
 		}
+	}
+
+	// - Think about the arguments.
+	OutputParams np = runparams;
+	np.docbook_in_par = true;
+	for (auto const & arg : prependedArguments)
+		arg->docbook(xs, np);
+
+	// - Mark the newly generated arguments are not-to-be-generated-again.
+	runparams.docbook_prepended_arguments = std::move(prependedArguments);
 
+	// - Deal with the first item.
+	if (writeOuterTag) {
 		if (!il.docbookitemwrappertag().empty() && il.docbookitemwrappertag() != "NONE" && il.docbookitemwrappertag() != "IGNORE")
 			xml::openTag(xs, il.docbookitemwrappertag(), il.docbookitemwrapperattr(), il.docbookitemwrappertagtype());
 
@@ -650,11 +689,13 @@ void InsetText::docbook(XMLStream & xs, OutputParams const & rp, XHTMLOptions op
 	if (il.isPassThru())
 		runparams.pass_thru = true;
 
+	// - Write the main content of the inset.
 	xs.startDivision(false);
 	docbookParagraphs(text_, buffer(), xs, runparams);
 	xs.endDivision();
 
-	if (opts & WriteOuterTag) {
+	// - Close the required tags.
+	if (writeOuterTag) {
 		if (!il.docbookitemtag().empty() && il.docbookitemtag() != "NONE" && il.docbookitemtag() != "IGNORE")
 			xml::closeTag(xs, il.docbookitemtag(), il.docbookitemtagtype());
 
diff --git a/src/output_docbook.cpp b/src/output_docbook.cpp
index d815abc..aaa3860 100644
--- a/src/output_docbook.cpp
+++ b/src/output_docbook.cpp
@@ -347,7 +347,7 @@ void makeParagraph(
 			special_case = true;
 	}
 
-	size_t nInsets = std::distance(par->insetList().begin(), par->insetList().end());
+	auto nInsets = std::distance(par->insetList().begin(), par->insetList().end());
 	auto parSize = (size_t) par->size();
 
 	// Plain layouts must be ignored.
@@ -377,6 +377,40 @@ void makeParagraph(
 	};
 	special_case |= nInsets == parSize && std::all_of(par->insetList().begin(), par->insetList().end(), isLyxCodeSpecialCase);
 
+	// Flex elements (InsetLayout) have their own parameter to control the special case.
+	auto isFlexSpecialCase = [](InsetList::Element inset) {
+		if (inset.inset->lyxCode() != FLEX_CODE)
+			return false;
+		// Standard condition: check the parameter.
+		if (inset.inset->getLayout().docbooknotinpara())
+			return true;
+
+		// If the parameter is not set, maybe the flex inset only contains things that should match the standard
+		// condition. In this case, isLyxCodeSpecialCase must also check for bibitems...
+		auto isLyxCodeSpecialCase = [](InsetList::Element inset) {
+			return lyxCodeSpecialCases.find(inset.inset->lyxCode()) != lyxCodeSpecialCases.end() ||
+					inset.inset->lyxCode() == BIBITEM_CODE;
+		};
+		if (InsetText * text = inset.inset->asInsetText()) {
+			for (auto const & par : text->paragraphs()) {
+				auto nInsets = std::distance(par.insetList().begin(), par.insetList().end());
+				auto parSize = (size_t) par.size();
+
+				if (nInsets == 1 && par.insetList().begin()->inset->lyxCode() == BIBITEM_CODE)
+					return true;
+				if (nInsets != parSize)
+					return false;
+				if (!std::all_of(par.insetList().begin(), par.insetList().end(), isLyxCodeSpecialCase))
+					return false;
+			}
+			return true;
+		}
+
+		// No case matched: give up.
+		return false;
+	};
+	special_case |= nInsets == parSize && std::all_of(par->insetList().begin(), par->insetList().end(), isFlexSpecialCase);
+
 	// Open a paragraph if it is allowed, we are not already within a paragraph, and the insets in the paragraph do
 	// not forbid paragraphs (aka special cases).
 	bool const open_par = runparams.docbook_make_pars


More information about the lyx-cvs mailing list