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).
This commit is contained in:
Thibaut Cuvelier 2020-08-26 21:19:38 +02:00
parent faaf780bed
commit 52b2d3f683
9 changed files with 175 additions and 129 deletions

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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;
}

View File

@ -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.

View File

@ -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();
}

View File

@ -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.
}

View File

@ -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);
// 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);
docstring cleaned = os2.str();
cleaned.erase(std::remove_if(cleaned.begin(), cleaned.end(), ::isspace), cleaned.end());
xs << XMLStream::ESCAPE_NONE << parXML;
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);
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);
}

View File

@ -132,8 +132,6 @@ private:
TagDeque tag_stack_;
///
bool is_last_tag_cr_;
public:
bool pending_tags_empty() { return pending_tags_.empty();};
};
namespace xml {