odocstream::pos_type const len = os.os().tellp();
if (inset->forceLTR(runparams)
+ // babel with Xe/LuaTeX does not need a switch
+ // and \L is not defined there.
+ && (!runparams.isFullUnicode() || !runparams.use_babel)
&& running_font.isRightToLeft()
// ERT is an exception, it should be output with no
// decorations at all
&& inset->lyxCode() != ERT_CODE) {
- if (runparams.use_polyglossia) {
+ if (runparams.use_polyglossia)
+ // (lua)bidi
os << "\\LRE{";
- } else if (running_font.language()->lang() == "farsi"
- || running_font.language()->lang() == "arabic_arabi")
+ else if (running_font.language()->lang() == "farsi"
+ || running_font.language()->lang() == "arabic_arabi")
os << "\\textLR{" << termcmd;
else
+ // babel classic
os << "\\L{";
close = true;
}
case '}':
os << "\\braceright ";
return;
+ case '$':
+ os << "\\lyxdollar ";
+ return;
case '~':
os << "\\lyxtilde ";
return;
column = 0;
break;
case '.':
+ case '!':
+ case '?':
+ case ':':
+ case ';':
+ case ',':
+ case 0x061F: // ؟ U+061F ARABIC QUESTION MARK
+ case 0x061B: // ؛ U+061B ARABIC SEMICOLON
+ case 0x060C: // ، U+060C ARABIC COMMA
flushString(os, write_buffer);
if (i + 1 < size() && d->text_[i + 1] == ' ') {
- os << ".\n";
+ os << to_utf8(docstring(1, c)) << '\n';
column = 0;
} else
- os << '.';
+ os << to_utf8(docstring(1, c));
+ break;
+ case 0x2014: // — U+2014 EM DASH
+ case 0x3002: // 。 U+3002 IDEOGRAPHIC FULL STOP
+ case 0xFF01: // ! U+FF01 FULLWIDTH EXCLAMATION MARK
+ case 0xFF1F: // ? U+FF1F FULLWIDTH QUESTION MARK
+ case 0xFF1A: // : U+FF1A FULLWIDTH COLON
+ case 0xFF1B: // ; U+FF1B FULLWIDTH SEMICOLON
+ case 0xFF0C: // , U+FF0C FULLWIDTH COMMA
+ flushString(os, write_buffer);
+ os << to_utf8(docstring(1, c)) << '\n';
+ column = 0;
break;
default:
- if ((column > 70 && c == ' ')
- || column > 79) {
+ if (column > 500) {
flushString(os, write_buffer);
os << '\n';
column = 0;
// This should not happen, but if so, we take no chances.
LYXERR0("Paragraph::fontSpan: position not found in fontinfo table!");
- LASSERT(false, return FontSpan(pos, pos));
+ LASSERT(false, /**/);
+ return FontSpan(pos, pos);
}
char_type c = d->text_[pos];
// Return unchanged character in LTR languages
- // or if we use poylglossia/bidi (XeTeX).
- if (rp.useBidiPackage()
- || !getFontSettings(bparams, pos).isRightToLeft())
+ // or if we use poylglossia/bidi (XeTeX)
+ // or with babel and Xe/LuaTeX.
+ if (!getFontSettings(bparams, pos).isRightToLeft()
+ || rp.useBidiPackage()
+ || (rp.use_babel && rp.isFullUnicode()))
return c;
// Without polyglossia/bidi, we need to account for some special cases.
os << '}';
column += 1;
}
- if (closeLanguage)
+ if (closeLanguage) {
// Force language closing
current_font.setLanguage(basefont.language());
+ langClosed = true;
+ }
Font const nextfont = (i == body_pos-1) ? basefont : current_font;
bool needPar = false;
column += running_font.latexWriteEndChanges(
Change(Change::UNCHANGED), Change(Change::DELETED), rp);
}
// Has the language been closed in the latexWriteEndChanges() call above?
- langClosed = running_font.language() != basefont.language()
+ langClosed |= running_font.language() != basefont.language()
&& running_font.language() != nextfont.language()
&& (running_font.language()->encoding()->package() != Encoding::CJK);
running_font = basefont;
column += Changes::latexMarkChange(os, bparams,
Change(Change::UNCHANGED), change, rp);
}
- } else {
+ } else {// if fontswitch_inset
+ if (current_font != running_font || !langClosed)
+ // font is still open in fontswitch_insets if we have
+ // a non-lang font difference or if the language
+ // is the only difference but has not been forcedly
+ // closed meanwhile
+ open_font = true;
running_font = current_font;
- open_font &= !langClosed;
}
}
d->latexInset(bparams, os, rp, running_font,
basefont, real_outerfont, open_font,
runningChange, style, i, column, fontswitch_inset,
- closeLanguage, lang_switched_at_inset);
+ closeLanguage, (lang_switched_at_inset || langClosed));
if (fontswitch_inset) {
if (open_font) {
bool needPar = false;
bool is_last_par,
bool ignore_fonts) const
{
- std::vector<docstring> prependedParagraphs;
- std::vector<docstring> generatedParagraphs;
- std::vector<docstring> appendedParagraphs;
+ // Return values: segregation of the content of this paragraph.
+ std::vector<docstring> prependedParagraphs; // Anything that must be output before the main tag of this paragraph.
+ std::vector<docstring> generatedParagraphs; // The main content of the paragraph.
+ std::vector<docstring> appendedParagraphs; // Anything that must be output after the main tag of this paragraph.
+
+ // Internal string stream to store the output before being added to one of the previous lists.
odocstringstream os;
// If there is an argument that must be output before the main tag, do it before handling the rest of the paragraph.
// State variables for the main loop.
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).
- std::vector<char_type> delayedChars; // When a font tag ends with a space, output it after the closing font tag.
+ std::vector<docstring> delayedChars; // When a font tag ends with a space, output it after the closing font tag.
// This requires to store delayed characters at some point.
- DocBookFontState fs; // Track whether we have opened font tags
+ // Track whether we have opened font tags
+ DocBookFontState fs;
DocBookFontState old_fs = fs;
Layout const & style = *d->layout_;
- FontInfo font_old = style.labeltype == LABEL_MANUAL ? style.labelfont : style.font;
- string const default_family = buf.masterBuffer()->params().fonts_default_family;
+ // Conversion of the font opening/closing into DocBook tags.
vector<xml::FontTag> tagsToOpen;
vector<xml::EndFontTag> tagsToClose;
// Output one paragraph (i.e. one string entry in generatedParagraphs).
generatedParagraphs.push_back(os.str());
- // Create a new XMLStream for the new paragraph, completely independent from the previous one. This implies
+ // Create a new XMLStream for the new paragraph, completely independent of the previous one. This implies
// that the string stream must be reset.
os.str(from_ascii(""));
delete xs;
// Restore the fonts for the new paragraph, so that the right tags are opened for the new entry.
if (!ignore_fonts_i) {
- font_old = outerfont.fontInfo();
fs = old_fs;
}
}
// Determine which tags should be opened or closed regarding fonts.
+ FontInfo const font_old = (i == 0 ?
+ (style.labeltype == LABEL_MANUAL ? style.labelfont : style.font) :
+ getFont(buf.masterBuffer()->params(), i - 1, outerfont).fontInfo());
Font const font = getFont(buf.masterBuffer()->params(), i, outerfont);
- tie(tagsToOpen, tagsToClose) = computeDocBookFontSwitch(font_old, font, default_family, fs);
+ tie(tagsToOpen, tagsToClose) = computeDocBookFontSwitch(
+ font_old, font, buf.masterBuffer()->params().fonts_default_family, fs);
if (!ignore_fonts_i) {
vector<xml::EndFontTag>::const_iterator cit = tagsToClose.begin();
// Deal with the delayed characters *after* closing font tags.
if (!delayedChars.empty()) {
- for (char_type c: delayedChars)
- *xs << c;
+ for (const docstring& c: delayedChars)
+ *xs << XMLStream::ESCAPE_NONE << c;
delayedChars.clear();
}
}
} else {
char_type c = getUChar(buf.masterBuffer()->params(), rp, i);
- if (lyx::isSpace(c) && !ignore_fonts)
- delayedChars.push_back(c);
- else
- *xs << c;
+ if (lyx::isSpace(c) && !ignore_fonts) { // Delay spaces *after* the font-tag closure for cleaner output.
+ if (c == ' ' && (style.free_spacing || rp.free_spacing)) {
+ delayedChars.push_back(from_ascii(" "));
+ } else {
+ delayedChars.emplace_back(1, c);
+ }
+ } else { // No need to delay the character.
+ if (c == '\'' && !ignore_fonts)
+ *xs << XMLStream::ESCAPE_NONE << "’";
+ else
+ *xs << c;
+ }
}
- font_old = font.fontInfo();
}
// FIXME, this code is just imported from XHTML
xs->closeFontTags();
// Deal with the delayed characters *after* closing font tags.
- if (!delayedChars.empty())
- for (char_type c: delayedChars)
- *xs << c;
+ if (!delayedChars.empty()) {
+ for (const docstring &c: delayedChars)
+ *xs << XMLStream::ESCAPE_NONE << c;
+ delayedChars.clear();
+ }
// 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.
// 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;
-
- vector<xml::FontTag>::const_iterator sit = tagsToOpen.begin();
- vector<xml::FontTag>::const_iterator sen = tagsToOpen.end();
- for (; sit != sen; ++sit)
- xs << *sit;
-
+ for (auto const & t : tagsToClose)
+ xs << t;
+ for (auto const & t : tagsToOpen)
+ xs << t;
tagsToClose.clear();
tagsToOpen.clear();
char_type c = getUChar(buf.masterBuffer()->params(),
runparams, i);
if (c == ' ' && (style.free_spacing || runparams.free_spacing))
- xs << XMLStream::ESCAPE_NONE << " ";
+ xs << XMLStream::ESCAPE_NONE << " ";
+ else if (c == '\'')
+ xs << XMLStream::ESCAPE_NONE << "’";
else
xs << c;
}
else if (c == META_INSET && (options & AS_STR_INSETS)) {
if (c == META_INSET && (options & AS_STR_PLAINTEXT)) {
LASSERT(runparams != nullptr, return docstring());
- getInset(i)->plaintext(os, *runparams);
+ if (runparams->find_effective())
+ getInset(i)->toString(os);
+ else
+ getInset(i)->plaintext(os, *runparams);
} else if (c == META_INSET && (options & AS_STR_MATHED)
&& getInset(i)->lyxCode() == REF_CODE) {
Buffer const & buf = getInset(i)->buffer();