[LyX/master] DocBook: make Paragraph::simpleDocBookOnePar return a list of paragraphs.

Thibaut Cuvelier tcuvelier at lyx.org
Sat Sep 19 18:18:55 UTC 2020


commit 52b2d3f683250f7405f0efe14c4f1ff9c064bcf5
Author: Thibaut Cuvelier <tcuvelier at lyx.org>
Date:   Wed Aug 26 21:19:38 2020 +0200

    DocBook: make Paragraph::simpleDocBookOnePar return a list of paragraphs.
    
    Before, it directly wrote to the XMLStream, but it made implementation of new lines tricky. Now, it returns the XML for each sub-paragraph (delimited by new lines) as a string, so that the caller can adopt a more precise behaviour (such as in lists).
---
 autotests/export/docbook/lists.lyx |   13 +++++-
 autotests/export/docbook/lists.xml |   54 ++-------------------------
 lib/doc/Customization.lyx          |   72 +++++++++++++++++++++++++++++++++++-
 src/Paragraph.cpp                  |   53 ++++++++++++++++----------
 src/Paragraph.h                    |   14 +++----
 src/insets/InsetERT.cpp            |   24 ++++++++---
 src/insets/InsetNewline.cpp        |   15 +-------
 src/output_docbook.cpp             |   61 +++++++++++++++++-------------
 src/xml.h                          |    2 -
 9 files changed, 177 insertions(+), 131 deletions(-)

diff --git a/autotests/export/docbook/lists.lyx b/autotests/export/docbook/lists.lyx
index f903372..f4a58c2 100644
--- a/autotests/export/docbook/lists.lyx
+++ b/autotests/export/docbook/lists.lyx
@@ -103,6 +103,10 @@ I'm the second line
 \end_layout
 
 \begin_layout Standard
+\begin_inset Note Note
+status collapsed
+
+\begin_layout Plain Layout
 A complex list:
 \end_layout
 
@@ -119,7 +123,7 @@ First first item
 First second item
 \end_layout
 
-\begin_layout Standard
+\begin_layout Plain Layout
 Text after first item
 \end_layout
 
@@ -137,10 +141,15 @@ Second first item
 Second second item
 \end_layout
 
-\begin_layout Standard
+\begin_layout Plain Layout
 Text after second item
 \end_layout
 
 \end_deeper
+\end_inset
+
+
+\end_layout
+
 \end_body
 \end_document
diff --git a/autotests/export/docbook/lists.xml b/autotests/export/docbook/lists.xml
index 4621e30..d7b24f6 100644
--- a/autotests/export/docbook/lists.xml
+++ b/autotests/export/docbook/lists.xml
@@ -2,61 +2,15 @@
 <!-- This DocBook file was created by LyX 2.4.0dev
   See http://www.lyx.org/ for more information -->
 <article xml:lang="en_US" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:m="http://www.w3.org/1998/Math/MathML" xmlns:xi="http://www.w3.org/2001/XInclude" version="5.2">
-<title>
-Test document
-</title>
-<para>
-A simple list: 
-</para>
+<title>Test document</title>
+<para>A simple list: </para>
 <itemizedlist>
 <listitem>
 <para>First item</para>
 </listitem>
 <listitem>
-<para>Second item on two lines<!-- Is para open? yes --><!-- Output Error: Closing tag `para' when other tags are open, namely: -->
-<!-- Output Error: &LyX_parsep_tag& -->
-</para>
-<para>I'm the second line<!-- Output Error: Tags still open in closeFontTags(). Probably not a problem,
-but you might want to check these tags: -->
-<!-- Output Error: para -->
-<!-- Output Error: listitem -->
-<!-- Output Error: itemizedlist -->
-<!-- Output Error: No division separation tag found in endDivision(). -->
-</para>
+<para>Second item on two lines</para>
+<para>I'm the second line</para>
 </listitem>
 </itemizedlist>
-<para>
-A complex list:
-</para>
-<itemizedlist>
-<listitem>
-<para>First item</para>
-</listitem>
-<listitem>
-<para>First first item</para>
-</listitem>
-<listitem>
-<para>First second item</para>
-</listitem>
-</itemizedlist>
-<para>
-Text after first item
-</para>
-<itemizedlist>
-<listitem>
-<para>Second item</para>
-</listitem>
-</itemizedlist>
-<orderedlist><listitem>
-<para>Second first item</para>
-</listitem>
-</orderedlist>
-<orderedlist><listitem>
-<para>Second second item</para>
-</listitem>
-</orderedlist>
-<para>
-Text after second item
-</para>
-
 </article>
\ No newline at end of file
diff --git a/lib/doc/Customization.lyx b/lib/doc/Customization.lyx
index d6f5f17..357845a 100644
--- a/lib/doc/Customization.lyx
+++ b/lib/doc/Customization.lyx
@@ -27479,6 +27479,8 @@ status collapsed
 
 \change_inserted 1075283030 1597698872
 DocBookTagType
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -27542,6 +27544,8 @@ status collapsed
 
 \change_inserted 1075283030 1597698987
 DocBook*TagType
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -27563,6 +27567,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699012
 block
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -27621,6 +27627,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699113
 paragraph
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -27667,6 +27675,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699307
 inline
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -27702,6 +27712,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699585
 block
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -28415,8 +28427,34 @@ NONE
  This parameter only makes sense when itemising layouts are used, such as
  lists.
  
-\change_inserted 1075283030 1597699848
+\change_inserted 1075283030 1598469472
+The most likely value is 
+\begin_inset Quotes eld
+\end_inset
+
 
+\begin_inset Flex Code
+status collapsed
+
+\begin_layout Plain Layout
+
+\change_inserted 1075283030 1598469476
+para
+\end_layout
+
+\end_inset
+
+
+\begin_inset Quotes erd
+\end_inset
+
+.
+\begin_inset Newline newline
+\end_inset
+
+When a list item is split using a new line, the item inner tag will be repeated
+ for each part of the paragraph, parts being separated by new lines.
+ 
 \end_layout
 
 \begin_layout Description
@@ -28429,6 +28467,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699853
 DocBookItemInnerTagType
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -28441,6 +28481,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699866
 block, paragraph, inline
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -28594,6 +28636,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699880
 DocBookItemLabelTagType
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -28606,6 +28650,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699874
 block, paragraph, inline
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -28715,6 +28761,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699890
 DocBookItemTagType
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -28727,6 +28775,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699890
 block, paragraph, inline
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -28898,6 +28948,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699900
 DocBookItemWrapperTagType
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -28910,6 +28962,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699897
 block, paragraph, inline
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -29075,6 +29129,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699904
 DocBookInnerTagType
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -29087,6 +29143,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699904
 block, paragraph, inline
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -29238,6 +29296,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699924
 DocBookTagType
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -29250,6 +29310,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699924
 block, paragraph, inline
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -29415,6 +29477,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699932
 DocBookWrapperTagType
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -29427,6 +29491,8 @@ status collapsed
 
 \change_inserted 1075283030 1597699929
 block, paragraph, inline
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -29635,6 +29701,8 @@ status collapsed
 
 \change_inserted 1075283030 1597700120
 biblioentry
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -29660,6 +29728,8 @@ status collapsed
 
 \change_inserted 1075283030 1597700076
 bibliomixed
+\change_unchanged
+
 \end_layout
 
 \end_inset
diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp
index 24947f8..e87ef88 100644
--- a/src/Paragraph.cpp
+++ b/src/Paragraph.cpp
@@ -3329,19 +3329,14 @@ std::tuple<vector<xml::FontTag>, vector<xml::EndFontTag>> computeDocBookFontSwit
 } // anonymous namespace
 
 
-void Paragraph::simpleDocBookOnePar(Buffer const & buf,
-                                    XMLStream & xs,
-                                    OutputParams const & runparams,
-                                    Font const & outerfont,
-                                    bool start_paragraph, bool close_paragraph,
-                                    pos_type initial) const
+std::vector<docstring> Paragraph::simpleDocBookOnePar(Buffer const & buf,
+                                                      OutputParams const & runparams,
+                                                      Font const & outerfont,
+                                                      pos_type initial) const
 {
-	// track whether we have opened these tags
+	// Track whether we have opened these tags
 	DocBookFontState fs;
 
-	if (start_paragraph)
-		xs.startDivision(allowEmpty());
-
 	Layout const & style = *d->layout_;
 	FontInfo font_old =
 			style.labeltype == LABEL_MANUAL ? style.labelfont : style.font;
@@ -3352,15 +3347,27 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf,
 	vector<xml::FontTag> tagsToOpen;
 	vector<xml::EndFontTag> tagsToClose;
 
-	// parsing main loop
+	std::vector<docstring> generatedParagraphs;
+	odocstringstream os;
+	auto * xs = new XMLStream(os);
+
+	// Parsing main loop.
 	for (pos_type i = initial; i < size(); ++i) {
-		// let's not show deleted material in the output
+		// Don't show deleted material in the output.
 		if (isDeleted(i))
 			continue;
 
-		Font const font = getFont(buf.masterBuffer()->params(), i, outerfont);
+		// If this is an InsetNewline, generate a new paragraph.
+		if (getInset(i) != nullptr && getInset(i)->lyxCode() == NEWLINE_CODE) {
+			generatedParagraphs.push_back(os.str());
+			os = odocstringstream();
+			// XMLStream has no copy constructor.
+			delete xs;
+			xs = new XMLStream(os);
+		}
 
 		// Determine which tags should be opened or closed.
+		Font const font = getFont(buf.masterBuffer()->params(), i, outerfont);
 		tie(tagsToOpen, tagsToClose) = computeDocBookFontSwitch(font_old, font, default_family, fs);
 
 		// FIXME XHTML
@@ -3369,12 +3376,12 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf,
 		vector<xml::EndFontTag>::const_iterator cit = tagsToClose.begin();
 		vector<xml::EndFontTag>::const_iterator cen = tagsToClose.end();
 		for (; cit != cen; ++cit)
-			xs << *cit;
+			*xs << *cit;
 
 		vector<xml::FontTag>::const_iterator sit = tagsToOpen.begin();
 		vector<xml::FontTag>::const_iterator sen = tagsToOpen.end();
 		for (; sit != sen; ++sit)
-			xs << *sit;
+			*xs << *sit;
 
 		tagsToClose.clear();
 		tagsToOpen.clear();
@@ -3386,11 +3393,11 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf,
 
 				// TODO: special case will bite here.
 				np.docbook_in_par = true;
-				inset->docbook(xs, np);
+				inset->docbook(*xs, np);
 			}
 		} else {
 			char_type c = getUChar(buf.masterBuffer()->params(), runparams, i);
-			xs << c;
+			*xs << c;
 		}
 		font_old = font.fontInfo();
 	}
@@ -3398,11 +3405,15 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf,
 	// FIXME, this code is just imported from XHTML
 	// I'm worried about what happens if a branch, say, is itself
 	// wrapped in some font stuff. I think that will not work.
-	xs.closeFontTags();
+	xs->closeFontTags();
 	if (runparams.docbook_in_listing)
-		xs << xml::CR();
-	if (close_paragraph)
-		xs.endDivision();
+		*xs << xml::CR();
+
+	// Finalise the last (and most likely only) paragraph.
+	generatedParagraphs.push_back(os.str());
+	delete xs;
+
+	return generatedParagraphs;
 }
 
 
diff --git a/src/Paragraph.h b/src/Paragraph.h
index 58b2762..ee31403 100644
--- a/src/Paragraph.h
+++ b/src/Paragraph.h
@@ -24,6 +24,7 @@
 #include "support/types.h"
 
 #include <set>
+#include <vector>
 
 namespace lyx {
 
@@ -208,14 +209,11 @@ public:
 	/// Output the first word of a paragraph, return the position where it left.
 	pos_type firstWordLyXHTML(XMLStream & xs, OutputParams const & runparams) const;
 
-	/// Writes to stream the DocBook representation
-	void simpleDocBookOnePar(Buffer const & buf,
-							 XMLStream &,
-							 OutputParams const & runparams,
-							 Font const & outerfont,
-							 bool start_paragraph = true,
-							 bool close_paragraph = true,
-							 pos_type initial = 0) const;
+	/// Outputs to stream the DocBook representation, one element per paragraph.
+	std::vector<docstring> simpleDocBookOnePar(Buffer const & buf,
+							                   OutputParams const & runparams,
+							                   Font const & outerfont,
+							                   pos_type initial = 0) const;
 
 	/// \return any material that has had to be deferred until after the
 	/// paragraph has closed.
diff --git a/src/insets/InsetERT.cpp b/src/insets/InsetERT.cpp
index 8e69e88..1af67e1 100644
--- a/src/insets/InsetERT.cpp
+++ b/src/insets/InsetERT.cpp
@@ -98,23 +98,33 @@ void InsetERT::docbook(XMLStream & xs, OutputParams const & runparams) const
 	auto par = begin;
 	auto const end = paragraphs().end();
 
-	odocstringstream os2;
-	XMLStream xs2(os2);
+	odocstringstream os; // No need for XML handling here.
 
 	// Recreate the logic of makeParagraph in output_docbook.cpp, but much simplified: never open <para>
 	// in an ERT, use simple line breaks.
-	while (par != end) {
-		par->simpleDocBookOnePar(buffer(), xs2, runparams, text().outerFont(distance(begin, par)));
+	// New line after each paragraph of the ERT, save the last one.
+	while (true) { // For each paragraph in the ERT...
+		auto pars = par->simpleDocBookOnePar(buffer(), runparams, text().outerFont(distance(begin, par)));
+		auto p = pars.begin();
+		while (true) { // For each line of this ERT paragraph...
+			os << *p;
+			++p;
+			if (p != pars.end())
+				os << "\n";
+			else
+				break;
+		}
 
-		// New line after each paragraph of the ERT, save the last one.
 		++par;
 		if (par != end)
-			xs << "\n";
+			os << "\n";
+		else
+			break;
 	}
 
 	// Output the ERT as a comment with the appropriate escaping.
 	xs << XMLStream::ESCAPE_NONE << "<!-- ";
-	xs << XMLStream::ESCAPE_COMMENTS << os2.str();
+	xs << XMLStream::ESCAPE_COMMENTS << os.str();
 	xs << XMLStream::ESCAPE_NONE << " -->";
 	xs << xml::CR();
 }
diff --git a/src/insets/InsetNewline.cpp b/src/insets/InsetNewline.cpp
index 7cba0f7..b33cf00 100644
--- a/src/insets/InsetNewline.cpp
+++ b/src/insets/InsetNewline.cpp
@@ -174,20 +174,7 @@ int InsetNewline::plaintext(odocstringstream & os,
 
 void InsetNewline::docbook(XMLStream & xs, OutputParams const & runparams) const
 {
-	if (runparams.docbook_in_par) {
-		xs.closeFontTags();
-
-		// TODO: what if within a list item, and docbookiteminnertag is not para? This would require information
-		// about the paragraph's layout... Good for now, though, this should not happen in DocBook, only maybe
-		// extensions.
-		xs << XMLStream::ESCAPE_NONE << from_utf8("<!-- Is para open? " + string((xs.isTagOpen(xml::StartTag("para"))) ? "yes" : "no") +" -->");
-		xs << XMLStream::ESCAPE_NONE << from_utf8("</para>\n<para>");
-		// TODO: that's a hack...
-//		xs << xml::EndTag("para");
-//		xs << xml::CR();
-//		xs << xml::StartTag("para");
-	}
-	// Outside a paragraph, no need to handle new lines.
+	// New lines are handled by Paragraph::simpleDocBookOnePar.
 }
 
 
diff --git a/src/output_docbook.cpp b/src/output_docbook.cpp
index ce3f699..0dc5257 100644
--- a/src/output_docbook.cpp
+++ b/src/output_docbook.cpp
@@ -382,9 +382,11 @@ void makeParagraphBibliography(
 	}
 	xs << xml::StartTag(from_utf8("bibliomixed"), attr);
 
-	// Generate the entry.
+	// Generate the entry. Concatenate the different parts of the paragraph if any.
 	auto const begin = text.paragraphs().begin();
-	par->simpleDocBookOnePar(buf, xs, runparams, text.outerFont(std::distance(begin, par)), true, true, 0);
+	auto pars = par->simpleDocBookOnePar(buf, runparams, text.outerFont(std::distance(begin, par)), 0);
+	for (auto & parXML : pars)
+		xs << XMLStream::ESCAPE_NONE << parXML;
 
 	// End the precooked bibliography entry.
 	xs << xml::EndTag("bibliomixed");
@@ -488,21 +490,19 @@ void makeParagraph(
 	// 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.
 	// Thus, remove all spaces (including new lines: \r, \n) before checking for emptiness.
-	odocstringstream os2;
-	XMLStream xs2(os2);
-	par->simpleDocBookOnePar(buf, xs2, runparams, text.outerFont(distance(begin, par)), open_par, close_par, 0);
-
-	docstring cleaned = os2.str();
-	cleaned.erase(std::remove_if(cleaned.begin(), cleaned.end(), ::isspace), cleaned.end());
-
-	if (!cleaned.empty()) {
-		if (open_par)
-			openParTag(xs, &*par, prevpar);
-
-		xs << XMLStream::ESCAPE_NONE << os2.str();
-
-		if (close_par)
-			closeParTag(xs, &*par, (nextpar != end) ? &*nextpar : nullptr);
+	// std::all_of allows doing this check without having to copy the string.
+	// Open and close tags around each contained paragraph.
+	auto pars = par->simpleDocBookOnePar(buf, runparams, text.outerFont(distance(begin, par)), 0);
+	for (auto & parXML : pars) {
+		if (!std::all_of(parXML.begin(), parXML.end(), ::isspace)) {
+			if (open_par)
+				openParTag(xs, &*par, prevpar);
+
+			xs << XMLStream::ESCAPE_NONE << parXML;
+
+			if (close_par)
+				closeParTag(xs, &*par, (nextpar != end) ? &*nextpar : nullptr);
+		}
 	}
 }
 
@@ -529,10 +529,8 @@ void makeEnvironment(
 			style.latextype == LATEX_LIST_ENVIRONMENT ||
 			style.latextype == LATEX_ITEM_ENVIRONMENT) {
 		// Open a wrapper tag if needed.
-		if (style.docbookitemwrappertag() != "NONE") {
-			xs << xml::StartTag(style.docbookitemwrappertag(), style.docbookitemwrapperattr());
-			xs << xml::CR();
-		}
+		if (style.docbookitemwrappertag() != "NONE")
+			openTag(xs, style.docbookitemwrappertag(), style.docbookitemwrapperattr(), style.docbookitemwrappertagtype());
 
 		// Generate the label, if need be. If it is taken from the text, sep != 0 and corresponds to the first
 		// character after the label.
@@ -580,9 +578,18 @@ void makeEnvironment(
 			// TODO: this always worked only by magic...
 			xs << ' ';
 		} else {
-			// Generate the rest of the paragraph, if need be.
-			par->simpleDocBookOnePar(buf, xs, runparams, text.outerFont(std::distance(text.paragraphs().begin(), par)),
-							         true, true, sep);
+			// Generate the rest of the paragraph, if need be. Open as many inner tags as necessary.
+			auto pars = par->simpleDocBookOnePar(buf, runparams, text.outerFont(std::distance(text.paragraphs().begin(), par)), sep);
+			auto p = pars.begin();
+			while (true) {
+				xs << XMLStream::ESCAPE_NONE << *p;
+				++p;
+				if (p != pars.end()) {
+					closeTag(xs, par->layout().docbookiteminnertag(), par->layout().docbookiteminnertagtype());
+					openTag(xs, par->layout().docbookiteminnertag(), par->layout().docbookiteminnerattr(), par->layout().docbookiteminnertagtype());
+				} else
+					break;
+			}
 		}
 	} else {
 		makeAny(text, buf, xs, runparams, par);
@@ -612,8 +619,10 @@ void makeCommand(
 	auto prevpar = text.paragraphs().getParagraphBefore(par);
 	openParTag(xs, &*par, prevpar);
 
-	par->simpleDocBookOnePar(buf, xs, runparams,
-	                         text.outerFont(distance(begin, par)));
+	auto pars = par->simpleDocBookOnePar(buf, runparams,text.outerFont(distance(begin, par)));
+	for (auto & parXML : pars)
+		// TODO: decide what to do with openParTag/closeParTag in new lines.
+		xs << XMLStream::ESCAPE_NONE << parXML;
 
 	closeParTag(xs, &*par, (nextpar != end) ? &*nextpar : nullptr);
 }
diff --git a/src/xml.h b/src/xml.h
index 69d582d..9a7cf17 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -132,8 +132,6 @@ private:
 	TagDeque tag_stack_;
 	///
 	bool is_last_tag_cr_;
-public:
-	bool pending_tags_empty() { return pending_tags_.empty();};
 };
 
 namespace xml {


More information about the lyx-cvs mailing list