#include "Paragraph.h"
-#include "LayoutFile.h"
#include "Buffer.h"
#include "BufferParams.h"
+#include "BufferEncodings.h"
#include "Changes.h"
#include "Counters.h"
-#include "BufferEncodings.h"
#include "InsetList.h"
#include "Language.h"
#include "LaTeXFeatures.h"
#include "output_docbook.h"
#include "ParagraphParameters.h"
#include "SpellChecker.h"
-#include "xml.h"
#include "texstream.h"
-#include "TextClass.h"
#include "TexRow.h"
#include "Text.h"
+#include "TextClass.h"
#include "WordLangTuple.h"
#include "WordList.h"
#include "support/debug.h"
#include "support/docstring_list.h"
-#include "support/ExceptionMessage.h"
#include "support/gettext.h"
#include "support/lassert.h"
-#include "support/Length.h"
#include "support/lstrings.h"
#include "support/textutils.h"
-#include "output_docbook.h"
#include <atomic>
#include <sstream>
char_type const c,
otexstream & os,
pos_type i,
- unsigned int & column);
+ unsigned int & column) const;
///
bool latexSpecialTU(
char_type const c,
otexstream & os,
pos_type i,
- unsigned int & column);
+ unsigned int & column) const;
///
bool latexSpecialT3(
char_type const c,
otexstream & os,
pos_type i,
- unsigned int & column);
+ unsigned int & column) const;
///
void validate(LaTeXFeatures & features) const;
runparams.local_font = &basefont;
}
- if (fontswitch_inset && !closeLanguage && fontswitch_inset) {
+ if (fontswitch_inset && !closeLanguage) {
// The directionality has been switched at inset.
// Force markup inside.
runparams.local_font = &basefont;
// add location information and throw again.
e.par_id = id_;
e.pos = i;
- throw(e);
+ throw;
}
if (close)
bool Paragraph::Private::latexSpecialT1(char_type const c, otexstream & os,
- pos_type i, unsigned int & column)
+ pos_type i, unsigned int & column) const
{
switch (c) {
case '>':
bool Paragraph::Private::latexSpecialTU(char_type const c, otexstream & os,
- pos_type i, unsigned int & column)
+ pos_type i, unsigned int & column) const
{
// TU encoding is currently on par with T1.
return latexSpecialT1(c, os, i, column);
bool Paragraph::Private::latexSpecialT3(char_type const c, otexstream & os,
- pos_type /*i*/, unsigned int & column)
+ pos_type /*i*/, unsigned int & column) const
{
switch (c) {
case '*':
void Paragraph::write(ostream & os, BufferParams const & bparams,
- depth_type & dth) const
+ depth_type & depth) const
{
// The beginning or end of a deeper (i.e. nested) area?
- if (dth != d->params_.depth()) {
- if (d->params_.depth() > dth) {
- while (d->params_.depth() > dth) {
+ if (depth != d->params_.depth()) {
+ if (d->params_.depth() > depth) {
+ while (d->params_.depth() > depth) {
os << "\n\\begin_deeper";
- ++dth;
+ ++depth;
}
} else {
- while (d->params_.depth() < dth) {
+ while (d->params_.depth() < depth) {
os << "\n\\end_deeper";
- --dth;
+ --depth;
}
}
}
}
-void Paragraph::insert(pos_type start, docstring const & str,
+void Paragraph::insert(pos_type pos, docstring const & str,
Font const & font, Change const & change)
{
for (size_t i = 0, n = str.size(); i != n ; ++i)
- insertChar(start + i, str[i], font, change);
+ insertChar(pos + i, str[i], font, change);
}
if (closeLanguage)
// Force language closing
current_font.setLanguage(basefont.language());
+ Font const nextfont = (i == body_pos-1) ? basefont : current_font;
column += running_font.latexWriteEndChanges(
os, bparams, runparams, basefont,
- (i == body_pos-1) ? basefont : current_font,
- needPar);
+ nextfont, needPar);
if (in_ct_deletion) {
// We have to close and then reopen \lyxdeleted,
// as strikeout needs to be on lowest level.
column += Changes::latexMarkChange(os, bparams,
Change(Change::UNCHANGED), Change(Change::DELETED), rp);
}
- running_font = basefont;
open_font = false;
- langClosed = true;
+ // Has the language been closed in the latexWriteEndChanges() call above?
+ langClosed = running_font.language() != basefont.language()
+ && running_font.language() != nextfont.language()
+ && (running_font.language()->encoding()->package() != Encoding::CJK);
+ running_font = basefont;
}
// if necessary, close language environment before opening CJK
// add location information and throw again.
e.par_id = id();
e.pos = i;
- throw(e);
+ throw;
}
}
}
std::vector<docstring> Paragraph::simpleDocBookOnePar(Buffer const & buf,
OutputParams const & runparams,
Font const & outerfont,
- pos_type initial) const
+ pos_type initial,
+ bool is_last_par,
+ bool ignore_fonts) const
{
// Track whether we have opened these tags
DocBookFontState fs;
vector<xml::EndFontTag> tagsToClose;
std::vector<docstring> generatedParagraphs;
+ DocBookFontState old_fs = fs;
odocstringstream os;
auto * xs = new XMLStream(os); // XMLStream has no copy constructor: to create a new object, the only solution
// is to hold a pointer to the XMLStream (xs = XMLStream(os) is not allowed once the first object is built).
+ // When a font tag ends with a space, output it after the closing font tag. This requires to store delayed
+ // characters at some point.
+ std::vector<char_type> delayedChars;
+
// Parsing main loop.
for (pos_type i = initial; i < size(); ++i) {
// Don't show deleted material in the output.
if (isDeleted(i))
continue;
- // If this is an InsetNewline, generate a new paragraph.
- if (getInset(i) != nullptr && getInset(i)->lyxCode() == NEWLINE_CODE) {
+ // If this is an InsetNewline, generate a new paragraph. Also reset the fonts, so that tags are closed in
+ // this paragraph.
+ if (getInset(i) && getInset(i)->lyxCode() == NEWLINE_CODE) {
+ if (!ignore_fonts)
+ xs->closeFontTags();
+
+ // Output one paragraph (i.e. one string entry in generatedParagraphs).
generatedParagraphs.push_back(os.str());
- os = odocstringstream();
+
+ // Create a new XMLStream for the new paragraph, completely independent from the previous one. This implies
+ // that the string stream must be reset.
+ os.str(from_ascii(""));
delete xs;
xs = new XMLStream(os);
+
+ // Restore the fonts for the new paragraph, so that the right tags are opened for the new entry.
+ if (!ignore_fonts) {
+ font_old = outerfont.fontInfo();
+ fs = old_fs;
+ }
}
- // Determine which tags should be opened or closed.
+ // Determine which tags should be opened or closed regarding fonts.
Font const font = getFont(buf.masterBuffer()->params(), i, outerfont);
- tie(tagsToOpen, tagsToClose) = computeDocBookFontSwitch(font_old, font, default_family, fs);
-
- // FIXME XHTML
- // Other such tags? What about the other text ranges?
-
- vector<xml::EndFontTag>::const_iterator cit = tagsToClose.begin();
- vector<xml::EndFontTag>::const_iterator cen = tagsToClose.end();
- for (; cit != cen; ++cit)
- *xs << *cit;
+ if (!ignore_fonts) {
+ tie(tagsToOpen, tagsToClose) = computeDocBookFontSwitch(font_old, font, default_family, fs);
+
+ // FIXME XHTML
+ // Other such tags? What about the other text ranges?
+
+ vector<xml::EndFontTag>::const_iterator cit = tagsToClose.begin();
+ vector<xml::EndFontTag>::const_iterator cen = tagsToClose.end();
+ for (; cit != cen; ++cit)
+ *xs << *cit;
+
+ // Deal with the delayed characters *after* closing font tags.
+ if (!delayedChars.empty()) {
+ for (char_type c: delayedChars)
+ *xs << c;
+ delayedChars.clear();
+ }
- vector<xml::FontTag>::const_iterator sit = tagsToOpen.begin();
- vector<xml::FontTag>::const_iterator sen = tagsToOpen.end();
- for (; sit != sen; ++sit)
- *xs << *sit;
+ vector<xml::FontTag>::const_iterator sit = tagsToOpen.begin();
+ vector<xml::FontTag>::const_iterator sen = tagsToOpen.end();
+ for (; sit != sen; ++sit)
+ *xs << *sit;
- tagsToClose.clear();
- tagsToOpen.clear();
+ tagsToClose.clear();
+ tagsToOpen.clear();
+ }
if (Inset const * inset = getInset(i)) {
if (!runparams.for_toc || inset->isInToc()) {
}
} else {
char_type c = getUChar(buf.masterBuffer()->params(), runparams, i);
- *xs << c;
+ if (lyx::isSpace(c) && !ignore_fonts)
+ delayedChars.push_back(c);
+ else
+ *xs << c;
}
font_old = font.fontInfo();
}
// 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();
- if (runparams.docbook_in_listing)
+ if (!ignore_fonts)
+ xs->closeFontTags();
+
+ // Deal with the delayed characters *after* closing font tags.
+ if (!delayedChars.empty())
+ for (char_type c: delayedChars)
+ *xs << c;
+
+ // In listings, new lines (i.e. \n characters in the output) are very important. Avoid generating one for the
+ // last line to get a clean output.
+ if (runparams.docbook_in_listing && !is_last_par)
*xs << xml::CR();
// Finalise the last (and most likely only) paragraph.
char_type const c = d->text_[pos];
if (c != '-' && c != '\'')
return false;
- int nextpos = pos + 1;
- int prevpos = pos > 0 ? pos - 1 : 0;
+ pos_type nextpos = pos + 1;
+ pos_type prevpos = pos > 0 ? pos - 1 : 0;
if ((nextpos == psize || isSpace(nextpos))
&& (pos == 0 || isSpace(prevpos)))
return false;
Inset const * ins = getInset(i);
if (ins->needsCProtection(maintext, fragile))
return true;
- if (ins->getLayout().latextype() == InsetLayout::ENVIRONMENT)
- // Environments need cprotection regardless the content
- return true;
// Now check math environments
InsetMath const * im = getInset(i)->asInsetMath();
if (!im || im->cell(0).empty())
}
-void Paragraph::setPlainOrDefaultLayout(DocumentClass const & tclass)
+void Paragraph::setPlainOrDefaultLayout(DocumentClass const & tc)
{
if (usePlainLayout())
- setPlainLayout(tclass);
+ setPlainLayout(tc);
else
- setDefaultLayout(tclass);
+ setDefaultLayout(tc);
}
}
int erasePos = pos - changes.size();
- for (size_t i = 0; i < changes.size(); i++) {
- insertChar(pos, changes[i].first,
- changes[i].second,
- trackChanges);
+ for (auto const & change : changes) {
+ insertChar(pos, change.first, change.second, trackChanges);
if (!eraseChar(erasePos, trackChanges)) {
++erasePos;
++pos; // advance
// start the spell checker on the unit of meaning
docstring word = asString(first, last, AS_STR_INSETS + AS_STR_SKIPDELETE);
WordLangTuple wl = WordLangTuple(word, lang);
- SpellChecker::Result result = word.size() ?
+ SpellChecker::Result result = !word.empty() ?
speller->check(wl) : SpellChecker::WORD_OK;
d->markMisspelledWords(first, last, result, word, skips);
first = ++last;