X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FParagraph.cpp;h=94cf9313d53d6eebc9e901114221cadf0ab56db6;hb=3bc08a76c42cd350a3141f00f37082bc9fab8967;hp=ea2c8366a06755a8e818d9654c6d8cfa64d7d673;hpb=37f41fd4b56c54764014c93c003be555f3fd6421;p=lyx.git diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index ea2c8366a0..94cf9313d5 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -25,7 +25,7 @@ #include "BufferParams.h" #include "Changes.h" #include "Counters.h" -#include "Encoding.h" +#include "BufferEncodings.h" #include "InsetList.h" #include "Language.h" #include "LaTeXFeatures.h" @@ -40,6 +40,7 @@ #include "ParagraphParameters.h" #include "SpellChecker.h" #include "sgml.h" +#include "texstream.h" #include "TextClass.h" #include "TexRow.h" #include "Text.h" @@ -60,6 +61,7 @@ #include "support/lstrings.h" #include "support/textutils.h" +#include #include #include @@ -96,7 +98,7 @@ public: /// void result(SpellChecker::Result r) { result_ = r; } /// - bool inside(pos_type pos) const { return range_.inside(pos); } + bool contains(pos_type pos) const { return range_.contains(pos); } /// bool covered(FontSpan const & r) const { @@ -104,8 +106,9 @@ public: // 2. last of new range inside current range or // 3. first of current range inside new range or // 4. last of current range inside new range - return range_.inside(r.first) || range_.inside(r.last) || - r.inside(range_.first) || r.inside(range_.last); + //FIXME: is this the same as !range_.intersect(r).empty() ? + return range_.contains(r.first) || range_.contains(r.last) || + r.contains(range_.first) || r.contains(range_.last); } /// void shift(pos_type pos, int offset) @@ -191,7 +194,7 @@ public: RangesIterator et = ranges_.end(); RangesIterator it = ranges_.begin(); for (; it != et; ++it) { - if(it->inside(pos)) { + if(it->contains(pos)) { return it->result(); } } @@ -205,7 +208,7 @@ public: RangesIterator et = ranges_.end(); RangesIterator it = ranges_.begin(); for (; it != et; ++it) { - if(it->inside(pos)) { + if(it->contains(pos)) { return it->range(); } } @@ -281,6 +284,11 @@ private: class Paragraph::Private { + // Enforce our own "copy" constructor + Private(Private const &) = delete; + Private & operator=(Private const &) = delete; + // Unique ID generator + static int make_id(); public: /// Private(Paragraph * owner, Layout const & layout); @@ -358,19 +366,6 @@ public: otexstream & os, pos_type i, unsigned int & column); - /// - bool latexSpecialTypewriter( - char_type const c, - otexstream & os, - pos_type i, - unsigned int & column); - /// - bool latexSpecialPhrase( - otexstream & os, - pos_type & i, - pos_type end_pos, - unsigned int & column, - OutputParams const & runparams); /// void validate(LaTeXFeatures & features) const; @@ -379,9 +374,6 @@ public: bool onlyText(Buffer const & buf, Font const & outerfont, pos_type initial) const; - /// match a string against a particular point in the paragraph - bool isTextAt(string const & str, pos_type pos) const; - /// a vector of speller skip positions typedef vector SkipPositions; typedef SkipPositions::const_iterator SkipPositionsIterator; @@ -499,7 +491,7 @@ public: TextContainer text_; typedef set Words; - typedef map LangWordsMap; + typedef map LangWordsMap; /// LangWordsMap words_; /// @@ -509,26 +501,6 @@ public: }; -namespace { - -struct special_phrase { - string phrase; - docstring macro; - bool builtin; -}; - -special_phrase const special_phrases[] = { - { "LyX", from_ascii("\\LyX{}"), false }, - { "TeX", from_ascii("\\TeX{}"), true }, - { "LaTeX2e", from_ascii("\\LaTeXe{}"), true }, - { "LaTeX", from_ascii("\\LaTeX{}"), true }, -}; - -size_t const phrases_nr = sizeof(special_phrases)/sizeof(special_phrase); - -} // namespace anon - - Paragraph::Private::Private(Paragraph * owner, Layout const & layout) : owner_(owner), inset_owner_(0), id_(-1), begin_of_body_(0), layout_(&layout) { @@ -536,33 +508,37 @@ Paragraph::Private::Private(Paragraph * owner, Layout const & layout) } -// Initialization of the counter for the paragraph id's, -// -// FIXME: There should be a more intelligent way to generate and use the -// paragraph ids per buffer instead a global static counter for all InsetText -// in the running program. -static int paragraph_id = -1; +//static +int Paragraph::Private::make_id() +{ + // The id is unique per session across buffers because it is used in + // LFUN_PARAGRAPH_GOTO to switch to a different buffer, for instance in the + // outliner. + // (thread-safe) + static atomic_uint next_id(0); + return next_id++; +} + Paragraph::Private::Private(Private const & p, Paragraph * owner) : owner_(owner), inset_owner_(p.inset_owner_), fontlist_(p.fontlist_), + id_(make_id()), params_(p.params_), changes_(p.changes_), insetlist_(p.insetlist_), begin_of_body_(p.begin_of_body_), text_(p.text_), words_(p.words_), layout_(p.layout_) { - id_ = ++paragraph_id; requestSpellCheck(p.text_.size()); } Paragraph::Private::Private(Private const & p, Paragraph * owner, pos_type beg, pos_type end) - : owner_(owner), inset_owner_(p.inset_owner_), + : owner_(owner), inset_owner_(p.inset_owner_), id_(make_id()), params_(p.params_), changes_(p.changes_), insetlist_(p.insetlist_, beg, end), begin_of_body_(p.begin_of_body_), words_(p.words_), layout_(p.layout_) { - id_ = ++paragraph_id; if (beg >= pos_type(p.text_.size())) return; text_ = p.text_.substr(beg, end - beg); @@ -585,16 +561,28 @@ Paragraph::Private::Private(Private const & p, Paragraph * owner, void Paragraph::addChangesToToc(DocIterator const & cdit, - Buffer const & buf) const + Buffer const & buf, bool output_active) const +{ + d->changes_.addToToc(cdit, buf, output_active); +} + + +void Paragraph::addChangesToBuffer(Buffer const & buf) const +{ + d->changes_.updateBuffer(buf); +} + + +bool Paragraph::isChangeUpdateRequired() const { - d->changes_.addToToc(cdit, buf); + return d->changes_.isUpdateRequired(); } bool Paragraph::isDeleted(pos_type start, pos_type end) const { - LASSERT(start >= 0 && start <= size(), /**/); - LASSERT(end > start && end <= size() + 1, /**/); + LASSERT(start >= 0 && start <= size(), return false); + LASSERT(end > start && end <= size() + 1, return false); return d->changes_.isDeleted(start, end); } @@ -602,8 +590,8 @@ bool Paragraph::isDeleted(pos_type start, pos_type end) const bool Paragraph::isChanged(pos_type start, pos_type end) const { - LASSERT(start >= 0 && start <= size(), /**/); - LASSERT(end > start && end <= size() + 1, /**/); + LASSERT(start >= 0 && start <= size(), return false); + LASSERT(end > start && end <= size() + 1, return false); return d->changes_.isChanged(start, end); } @@ -615,7 +603,7 @@ bool Paragraph::isMergedOnEndOfParDeletion(bool trackChanges) const if (!trackChanges) return true; - Change const change = d->changes_.lookup(size()); + Change const & change = d->changes_.lookup(size()); return change.inserted() && change.currentAuthor(); } @@ -648,7 +636,7 @@ void Paragraph::setChange(Change const & change) void Paragraph::setChange(pos_type pos, Change const & change) { - LASSERT(pos >= 0 && pos <= size(), /**/); + LASSERT(pos >= 0 && pos <= size(), return); d->changes_.set(change, pos); // see comment in setChange(Change const &) above @@ -660,15 +648,15 @@ void Paragraph::setChange(pos_type pos, Change const & change) Change const & Paragraph::lookupChange(pos_type pos) const { - LASSERT(pos >= 0 && pos <= size(), /**/); + LBUFERR(pos >= 0 && pos <= size()); return d->changes_.lookup(pos); } void Paragraph::acceptChanges(pos_type start, pos_type end) { - LASSERT(start >= 0 && start <= size(), /**/); - LASSERT(end > start && end <= size() + 1, /**/); + LASSERT(start >= 0 && start <= size(), return); + LASSERT(end > start && end <= size() + 1, return); for (pos_type pos = start; pos < end; ++pos) { switch (lookupChange(pos).type) { @@ -702,8 +690,8 @@ void Paragraph::acceptChanges(pos_type start, pos_type end) void Paragraph::rejectChanges(pos_type start, pos_type end) { - LASSERT(start >= 0 && start <= size(), /**/); - LASSERT(end > start && end <= size() + 1, /**/); + LASSERT(start >= 0 && start <= size(), return); + LASSERT(end > start && end <= size() + 1, return); for (pos_type pos = start; pos < end; ++pos) { switch (lookupChange(pos).type) { @@ -738,7 +726,7 @@ void Paragraph::rejectChanges(pos_type start, pos_type end) void Paragraph::Private::insertChar(pos_type pos, char_type c, Change const & change) { - LASSERT(pos >= 0 && pos <= int(text_.size()), /**/); + LASSERT(pos >= 0 && pos <= int(text_.size()), return); // track change changes_.insert(change, pos); @@ -767,10 +755,10 @@ void Paragraph::Private::insertChar(pos_type pos, char_type c, bool Paragraph::insertInset(pos_type pos, Inset * inset, - Change const & change) + Font const & font, Change const & change) { - LASSERT(inset, /**/); - LASSERT(pos >= 0 && pos <= size(), /**/); + LASSERT(inset, return false); + LASSERT(pos >= 0 && pos <= size(), return false); // Paragraph::insertInset() can be used in cut/copy/paste operation where // d->inset_owner_ is not set yet. @@ -778,13 +766,14 @@ bool Paragraph::insertInset(pos_type pos, Inset * inset, return false; d->insertChar(pos, META_INSET, change); - LASSERT(d->text_[pos] == META_INSET, /**/); + LASSERT(d->text_[pos] == META_INSET, return false); // Add a new entry in the insetlist_. d->insetlist_.insert(inset, pos); // Some insets require run of spell checker requestSpellCheck(pos); + setFont(pos, font); return true; } @@ -846,8 +835,8 @@ bool Paragraph::eraseChar(pos_type pos, bool trackChanges) int Paragraph::eraseChars(pos_type start, pos_type end, bool trackChanges) { - LASSERT(start >= 0 && start <= size(), /**/); - LASSERT(end >= start && end <= size() + 1, /**/); + LASSERT(start >= 0 && start <= size(), return 0); + LASSERT(end >= start && end <= size() + 1, return 0); pos_type i = start; for (pos_type count = end - start; count; --count) { @@ -945,10 +934,13 @@ int Paragraph::Private::writeScriptChars(otexstream & os, { // FIXME: modifying i here is not very nice... - // We only arrive here when a proper language for character text_[i] has - // not been specified (i.e., it could not be translated in the current - // latex encoding) or its latex translation has been forced, and it - // belongs to a known script. + // We only arrive here when character text_[i] could not be translated + // into the current latex encoding (or its latex translation has been forced,) + // and it belongs to a known script. + // TODO: We need \textcyr and \textgreek wrappers also for characters + // that can be encoded in the "LaTeX encoding" but not in the + // current *font encoding*. + // (See #9681 for details and test) // Parameter ltx contains the latex translation of text_[i] as specified // in the unicodesymbols file and is something like "\textXXX{}". // The latex macro name "textXXX" specifies the script to which text_[i] @@ -964,6 +956,10 @@ int Paragraph::Private::writeScriptChars(otexstream & os, bool closing_brace = true; if (script == "textgreek" && encoding.latexName() == "iso-8859-7") { // Correct encoding is being used, so we can avoid \textgreek. + // TODO: wrong test: we need to check the *font encoding* + // (i.e. the active language and its FontEncoding tag) + // instead of the LaTeX *input encoding*! + // See #9637 for details and test-cases. pos = brace1 + 1; length -= pos; closing_brace = false; @@ -1010,26 +1006,6 @@ int Paragraph::Private::writeScriptChars(otexstream & os, } -bool Paragraph::Private::isTextAt(string const & str, pos_type pos) const -{ - pos_type const len = str.length(); - - // is the paragraph large enough? - if (pos + len > int(text_.size())) - return false; - - // does the wanted text start at point? - for (string::size_type i = 0; i < str.length(); ++i) { - // Caution: direct comparison of characters works only - // because str is pure ASCII. - if (str[i] != text_[pos + i]) - return false; - } - - return fontlist_.hasChangeInRange(pos, len); -} - - void Paragraph::Private::latexInset(BufferParams const & bparams, otexstream & os, OutputParams & runparams, @@ -1043,15 +1019,17 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, unsigned int & column) { Inset * inset = owner_->getInset(i); - LASSERT(inset, /**/); + LBUFERR(inset); if (style.pass_thru) { - inset->plaintext(os.os(), runparams); + odocstringstream ods; + inset->plaintext(ods, runparams); + os << ods.str(); return; } // FIXME: move this to InsetNewline::latex - if (inset->lyxCode() == NEWLINE_CODE) { + if (inset->lyxCode() == NEWLINE_CODE || inset->lyxCode() == SEPARATOR_CODE) { // newlines are handled differently here than // the default in simpleTeXSpecialChars(). if (!style.newline_allowed) { @@ -1187,7 +1165,9 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, char_type const c = (runparams.use_polyglossia) ? owner_->getUChar(bparams, i) : text_[i]; - if (style.pass_thru || runparams.pass_thru) { + if (style.pass_thru || runparams.pass_thru + || contains(style.pass_thru_chars, c) + || contains(runparams.pass_thru_chars, c)) { if (c != '\0') { Encoding const * const enc = runparams.encoding; if (enc && !enc->encodable(c)) @@ -1202,16 +1182,11 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, return; // If T1 font encoding is used, use the special // characters it provides. - // NOTE: some languages reset the font encoding - // internally + // NOTE: Some languages reset the font encoding internally to a + // non-standard font encoding. If we are using such a language, + // we do not output special T1 chars. if (!runparams.inIPA && !running_font.language()->internalFontEncoding() - && lyxrc.fontenc == "T1" && latexSpecialT1(c, os, i, column)) - return; - - // \tt font needs special treatment - if (!runparams.inIPA - && running_font.fontInfo().family() == TYPEWRITER_FAMILY - && latexSpecialTypewriter(c, os, i, column)) + && bparams.font_encoding() == "T1" && latexSpecialT1(c, os, i, column)) return; // Otherwise, we use what LaTeX provides us. @@ -1234,6 +1209,16 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, break; case '-': os << '-'; + if (i + 1 < static_cast(text_.size()) && + (end_pos == -1 || i + 1 < end_pos) && + text_[i+1] == '-') { + // Prevent "--" becoming an endash and "---" becoming + // an emdash. + // Within \ttfamily, "--" is merged to "-" (no endash) + // so we avoid this rather irritating ligature as well + os << "{}"; + column += 2; + } break; case '\"': os << "\\char`\\\"{}"; @@ -1277,10 +1262,6 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, break; default: - // LyX, LaTeX etc. - if (latexSpecialPhrase(os, i, end_pos, column, runparams)) - return; - if (c == '\0') return; @@ -1299,7 +1280,7 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, docstring nextlatex; bool nexttipas = false; string nexttipashortcut; - if (next != '\0' && next != META_INSET) { + if (next != '\0' && next != META_INSET && encoding.encodable(next)) { nextlatex = encoding.latexChar(next).first; if (runparams.inIPA) { nexttipashortcut = Encodings::TIPAShortcut(next); @@ -1393,69 +1374,20 @@ bool Paragraph::Private::latexSpecialT3(char_type const c, otexstream & os, } -bool Paragraph::Private::latexSpecialTypewriter(char_type const c, otexstream & os, - pos_type i, unsigned int & column) -{ - switch (c) { - case '-': - // within \ttfamily, "--" is merged to "-" (no endash) - // so we avoid this rather irritating ligature - if (i + 1 < int(text_.size()) && text_[i + 1] == '-') { - os << "-{}"; - column += 2; - } else - os << '-'; - return true; - - // everything else has to be checked separately - // (depending on the encoding) - default: - return false; - } -} - - -/// \param end_pos -/// If [start_pos, end_pos) does not include entirely the special phrase, then -/// do not apply the macro transformation. -bool Paragraph::Private::latexSpecialPhrase(otexstream & os, pos_type & i, pos_type end_pos, - unsigned int & column, OutputParams const & runparams) -{ - // FIXME: if we have "LaTeX" with a font - // change in the middle (before the 'T', then - // the "TeX" part is still special cased. - // Really we should only operate this on - // "words" for some definition of word - - for (size_t pnr = 0; pnr < phrases_nr; ++pnr) { - if (!isTextAt(special_phrases[pnr].phrase, i) - || (end_pos != -1 && i + int(special_phrases[pnr].phrase.size()) > end_pos)) - continue; - if (runparams.moving_arg) - os << "\\protect"; - os << special_phrases[pnr].macro; - i += special_phrases[pnr].phrase.length() - 1; - column += special_phrases[pnr].macro.length() - 1; - return true; - } - return false; -} - - void Paragraph::Private::validate(LaTeXFeatures & features) const { if (layout_->inpreamble && inset_owner_) { bool const is_command = layout_->latextype == LATEX_COMMAND; Buffer const & buf = inset_owner_->buffer(); - BufferParams const & bp = buf.params(); + BufferParams const & bp = features.runparams().is_child + ? buf.masterParams() : buf.params(); Font f; - TexRow texrow; // Using a string stream here circumvents the encoding // switching machinery of odocstream. Therefore the // output is wrong if this paragraph contains content // that needs to switch encoding. odocstringstream ods; - otexstream os(ods, texrow); + otexstream os(ods); if (is_command) { os << '\\' << from_ascii(layout_->latexname()); // we have to provide all the optional arguments here, even though @@ -1481,7 +1413,7 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const } } string const snippet = to_utf8(ods.str()); - features.addPreambleSnippet(snippet); + features.addPreambleSnippet(snippet, true); } } @@ -1518,14 +1450,7 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const // then the contents for (pos_type i = 0; i < int(text_.size()) ; ++i) { - for (size_t pnr = 0; pnr < phrases_nr; ++pnr) { - if (!special_phrases[pnr].builtin - && isTextAt(special_phrases[pnr].phrase, i)) { - features.require(special_phrases[pnr].phrase); - break; - } - } - Encodings::validate(text_[i], features); + BufferEncodings::validate(text_[i], features); } } @@ -1631,7 +1556,7 @@ void Paragraph::write(ostream & os, BufferParams const & bparams, int column = 0; for (pos_type i = 0; i <= size(); ++i) { - Change const change = lookupChange(i); + Change const & change = lookupChange(i); if (change != running_change) flushString(os, write_buffer); Changes::lyxMarkChange(os, bparams, column, running_change, change); @@ -1667,6 +1592,9 @@ void Paragraph::write(ostream & os, BufferParams const & bparams, os << "\n\\end_inset\n\n"; column = 0; } + // FIXME This can be removed again once the mystery + // crash has been resolved. + os << flush; } break; case '\\': @@ -1702,6 +1630,9 @@ void Paragraph::write(ostream & os, BufferParams const & bparams, flushString(os, write_buffer); os << "\n\\end_layout\n"; + // FIXME This can be removed again once the mystery + // crash has been resolved. + os << flush; } @@ -1780,16 +1711,6 @@ void Paragraph::insertChar(pos_type pos, char_type c, } -bool Paragraph::insertInset(pos_type pos, Inset * inset, - Font const & font, Change const & change) -{ - bool const success = insertInset(pos, inset, change); - // Set the font/language of the inset... - setFont(pos, font); - return success; -} - - void Paragraph::resetFonts(Font const & font) { d->fontlist_.clear(); @@ -1803,7 +1724,7 @@ Font const & Paragraph::getFontSettings(BufferParams const & bparams, { if (pos > size()) { LYXERR0("pos: " << pos << " size: " << size()); - LASSERT(pos <= size(), /**/); + LBUFERR(false); } FontList::const_iterator cit = d->fontlist_.fontIterator(pos); @@ -1828,9 +1749,12 @@ Font const & Paragraph::getFontSettings(BufferParams const & bparams, FontSpan Paragraph::fontSpan(pos_type pos) const { - LASSERT(pos <= size(), /**/); - pos_type start = 0; + LBUFERR(pos <= size()); + if (pos == size()) + return FontSpan(pos, pos); + + pos_type start = 0; FontList::const_iterator cit = d->fontlist_.begin(); FontList::const_iterator end = d->fontlist_.end(); for (; cit != end; ++cit) { @@ -1847,8 +1771,8 @@ FontSpan Paragraph::fontSpan(pos_type pos) const } // This should not happen, but if so, we take no chances. - // LYXERR0("Paragraph::getEndPosOfFontSpan: This should not happen!"); - return FontSpan(pos, pos); + LYXERR0("Paragraph::fontSpan: position not found in fontinfo table!"); + LASSERT(false, return FontSpan(pos, pos)); } @@ -1879,7 +1803,7 @@ Font const & Paragraph::getFirstFontSettings(BufferParams const & bparams) const Font const Paragraph::getFont(BufferParams const & bparams, pos_type pos, Font const & outerfont) const { - LASSERT(pos >= 0, /**/); + LBUFERR(pos >= 0); Font font = getFontSettings(bparams, pos); @@ -1917,18 +1841,10 @@ Font const Paragraph::getLayoutFont } -/// Returns the height of the highest font in range -FontSize Paragraph::highestFontInRange - (pos_type startpos, pos_type endpos, FontSize def_size) const -{ - return d->fontlist_.highestInRange(startpos, endpos, def_size); -} - - char_type Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const { char_type c = d->text_[pos]; - if (!lyxrc.rtl_support || !getFontSettings(bparams, pos).isRightToLeft()) + if (!getFontSettings(bparams, pos).isRightToLeft()) return c; // FIXME: The arabic special casing is due to the difference of arabic @@ -1972,7 +1888,7 @@ char_type Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const void Paragraph::setFont(pos_type pos, Font const & font) { - LASSERT(pos <= size(), /**/); + LASSERT(pos <= size(), return); // First, reduce font against layout/label font // Update: The setCharFont() routine in text2.cpp already @@ -2084,8 +2000,7 @@ docstring Paragraph::expandParagraphLabel(Layout const & layout, bool const in_appendix = process_appendix && d->params_.appendix(); docstring fmt = translateIfPossible(layout.labelstring(in_appendix), lang); - if (fmt.empty() && layout.labeltype == LABEL_COUNTER - && !layout.counter.empty()) + if (fmt.empty() && !layout.counter.empty()) return tclass.counters().theCounter(layout.counter, lang); // handle 'inherited level parts' in 'fmt', @@ -2097,7 +2012,7 @@ docstring Paragraph::expandParagraphLabel(Layout const & layout, docstring parent(fmt, i + 1, j - i - 1); docstring label = from_ascii("??"); if (tclass.hasLayout(parent)) - docstring label = expandParagraphLabel(tclass[parent], bparams, + label = expandParagraphLabel(tclass[parent], bparams, process_appendix); fmt = docstring(fmt, 0, i) + label + docstring(fmt, j + 1, docstring::npos); @@ -2139,17 +2054,15 @@ void Paragraph::setBeginOfBody() // remove unnecessary getChar() calls pos_type i = 0; pos_type end = size(); - if (i < end && !isNewline(i)) { + if (i < end && !(isNewline(i) || isEnvSeparator(i))) { ++i; - char_type previous_char = 0; - char_type temp = 0; if (i < end) { - previous_char = d->text_[i]; - if (!isNewline(i)) { + char_type previous_char = d->text_[i]; + if (!(isNewline(i) || isEnvSeparator(i))) { ++i; while (i < end && previous_char != ' ') { - temp = d->text_[i]; - if (isNewline(i)) + char_type temp = d->text_[i]; + if (isNewline(i) || isEnvSeparator(i)) break; ++i; previous_char = temp; @@ -2204,36 +2117,37 @@ string correction(string const & orig) } -string const corrected_env(string const & suffix, string const & env, - InsetCode code, bool const lastpar) +bool corrected_env(otexstream & os, string const & suffix, string const & env, + InsetCode code, bool const lastpar, int & col) { - string output = suffix + "{"; + string macro = suffix + "{"; if (noTrivlistCentering(code)) { if (lastpar) { // the last paragraph in non-trivlist-aligned // context is special (to avoid unwanted whitespace) - if (suffix == "\\begin") - return "\\" + correction(env) + "{}"; - return string(); + if (suffix == "\\begin") { + macro = "\\" + correction(env) + "{}"; + os << from_ascii(macro); + col += macro.size(); + return true; + } + return false; } - output += correction(env); + macro += correction(env); } else - output += env; - output += "}"; - if (suffix == "\\begin") - output += "\n"; - return output; -} - - -void adjust_column(string const & str, int & column) -{ - if (!contains(str, "\n")) - column += str.size(); - else { - string tmp; - column = rsplit(str, tmp, '\n').size(); + macro += env; + macro += "}"; + if (suffix == "\\par\\end") { + os << breakln; + col = 0; + } + os << from_ascii(macro); + col += macro.size(); + if (suffix == "\\begin") { + os << breakln; + col = 0; } + return true; } } // namespace anon @@ -2244,7 +2158,12 @@ int Paragraph::Private::startTeXParParams(BufferParams const & bparams, { int column = 0; - if (params_.noindent() && !layout_->pass_thru) { + bool canindent = + (bparams.paragraph_separation == BufferParams::ParagraphIndentSeparation) ? + (layout_->toggle_indent != ITOGGLE_NEVER) : + (layout_->toggle_indent == ITOGGLE_ALWAYS); + + if (canindent && params_.noindent() && !layout_->pass_thru) { os << "\\noindent "; column += 10; } @@ -2283,28 +2202,19 @@ int Paragraph::Private::startTeXParParams(BufferParams const & bparams, case LYX_ALIGN_DECIMAL: break; case LYX_ALIGN_LEFT: { - string output; if (owner_->getParLanguage(bparams)->babel() != "hebrew") - output = corrected_env(begin_tag, "flushleft", code, lastpar); + corrected_env(os, begin_tag, "flushleft", code, lastpar, column); else - output = corrected_env(begin_tag, "flushright", code, lastpar); - os << from_ascii(output); - adjust_column(output, column); + corrected_env(os, begin_tag, "flushright", code, lastpar, column); break; } case LYX_ALIGN_RIGHT: { - string output; if (owner_->getParLanguage(bparams)->babel() != "hebrew") - output = corrected_env(begin_tag, "flushright", code, lastpar); + corrected_env(os, begin_tag, "flushright", code, lastpar, column); else - output = corrected_env(begin_tag, "flushleft", code, lastpar); - os << from_ascii(output); - adjust_column(output, column); + corrected_env(os, begin_tag, "flushleft", code, lastpar, column); break; } case LYX_ALIGN_CENTER: { - string output; - output = corrected_env(begin_tag, "center", code, lastpar); - os << from_ascii(output); - adjust_column(output, column); + corrected_env(os, begin_tag, "center", code, lastpar, column); break; } } @@ -2336,8 +2246,9 @@ bool Paragraph::Private::endTeXParParams(BufferParams const & bparams, break; } - string output; - string const end_tag = "\n\\par\\end"; + bool output = false; + int col = 0; + string const end_tag = "\\par\\end"; InsetCode code = ownerCode(); bool const lastpar = runparams.isLastPar; @@ -2350,26 +2261,23 @@ bool Paragraph::Private::endTeXParParams(BufferParams const & bparams, break; case LYX_ALIGN_LEFT: { if (owner_->getParLanguage(bparams)->babel() != "hebrew") - output = corrected_env(end_tag, "flushleft", code, lastpar); + output = corrected_env(os, end_tag, "flushleft", code, lastpar, col); else - output = corrected_env(end_tag, "flushright", code, lastpar); - os << from_ascii(output); + output = corrected_env(os, end_tag, "flushright", code, lastpar, col); break; } case LYX_ALIGN_RIGHT: { if (owner_->getParLanguage(bparams)->babel() != "hebrew") - output = corrected_env(end_tag, "flushright", code, lastpar); + output = corrected_env(os, end_tag, "flushright", code, lastpar, col); else - output = corrected_env(end_tag, "flushleft", code, lastpar); - os << from_ascii(output); + output = corrected_env(os, end_tag, "flushleft", code, lastpar, col); break; } case LYX_ALIGN_CENTER: { - output = corrected_env(end_tag, "center", code, lastpar); - os << from_ascii(output); + corrected_env(os, end_tag, "center", code, lastpar, col); break; } } - return !output.empty() || lastpar; + return output || lastpar; } @@ -2482,7 +2390,7 @@ void Paragraph::latex(BufferParams const & bparams, Change const & change = runparams.inDeletedInset ? runparams.changeOfDeletedInset : lookupChange(i); - if (bparams.outputChanges && runningChange != change) { + if (bparams.output_changes && runningChange != change) { if (open_font) { column += running_font.latexWriteEndChanges( os, bparams, runparams, basefont, basefont); @@ -2498,25 +2406,25 @@ void Paragraph::latex(BufferParams const & bparams, // do not output text which is marked deleted // if change tracking output is disabled - if (!bparams.outputChanges && change.deleted()) { + if (!bparams.output_changes && change.deleted()) { continue; } ++column; // Fully instantiated font - Font const font = getFont(bparams, i, outerfont); + Font const current_font = getFont(bparams, i, outerfont); Font const last_font = running_font; // Do we need to close the previous font? if (open_font && - (font != running_font || - font.language() != running_font.language())) + (current_font != running_font || + current_font.language() != running_font.language())) { column += running_font.latexWriteEndChanges( os, bparams, runparams, basefont, - (i == body_pos-1) ? basefont : font); + (i == body_pos-1) ? basefont : current_font); running_font = basefont; open_font = false; } @@ -2527,7 +2435,7 @@ void Paragraph::latex(BufferParams const & bparams, string const lang_end_command = runparams.use_polyglossia ? "\\end{$$lang}" : lyxrc.language_command_end; if (!running_lang.empty() && - font.language()->encoding()->package() == Encoding::CJK) { + current_font.language()->encoding()->package() == Encoding::CJK) { string end_tag = subst(lang_end_command, "$$lang", running_lang); @@ -2538,28 +2446,28 @@ void Paragraph::latex(BufferParams const & bparams, // Switch file encoding if necessary (and allowed) if (!runparams.pass_thru && !style.pass_thru && runparams.encoding->package() != Encoding::none && - font.language()->encoding()->package() != Encoding::none) { + current_font.language()->encoding()->package() != Encoding::none) { pair const enc_switch = switchEncoding(os.os(), bparams, runparams, - *(font.language()->encoding())); + *(current_font.language()->encoding())); if (enc_switch.first) { column += enc_switch.second; - runparams.encoding = font.language()->encoding(); + runparams.encoding = current_font.language()->encoding(); } } char_type const c = d->text_[i]; // Do we need to change font? - if ((font != running_font || - font.language() != running_font.language()) && + if ((current_font != running_font || + current_font.language() != running_font.language()) && i != body_pos - 1) { odocstringstream ods; - column += font.latexWriteStartChanges(ods, bparams, + column += current_font.latexWriteStartChanges(ods, bparams, runparams, basefont, last_font); - running_font = font; + running_font = current_font; open_font = true; docstring fontchange = ods.str(); // check whether the fontchange ends with a \\textcolor @@ -2585,7 +2493,7 @@ void Paragraph::latex(BufferParams const & bparams, // style.pass_thru is false. if (i != body_pos - 1) { if (d->simpleTeXBlanks(runparams, os, - i, column, font, style)) { + i, column, current_font, style)) { // A surrogate pair was output. We // must not call latexSpecialChar // in this iteration, since it would output @@ -2598,7 +2506,7 @@ void Paragraph::latex(BufferParams const & bparams, OutputParams rp = runparams; rp.free_spacing = style.free_spacing; - rp.local_font = &font; + rp.local_font = ¤t_font; rp.intitle = style.intitle; // Two major modes: LaTeX or plain @@ -2672,8 +2580,7 @@ void Paragraph::latex(BufferParams const & bparams, if (allowcust && d->endTeXParParams(bparams, os, runparams) && runparams.encoding != prev_encoding) { runparams.encoding = prev_encoding; - if (!runparams.isFullUnicode()) - os << setEncoding(prev_encoding->iconvName()); + os << setEncoding(prev_encoding->iconvName()); } LYXERR(Debug::LATEX, "Paragraph::latex... done " << this); @@ -2830,101 +2737,355 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf, } +namespace { +void doFontSwitch(vector & tagsToOpen, + vector & tagsToClose, + bool & flag, FontState curstate, html::FontTypes type) +{ + if (curstate == FONT_ON) { + tagsToOpen.push_back(html::FontTag(type)); + flag = true; + } else if (flag) { + tagsToClose.push_back(html::EndFontTag(type)); + flag = false; + } +} +} + + docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf, XHTMLStream & xs, OutputParams const & runparams, Font const & outerfont, + bool start_paragraph, bool close_paragraph, pos_type initial) const { docstring retval; + // track whether we have opened these tags bool emph_flag = false; bool bold_flag = false; + bool noun_flag = false; + bool ubar_flag = false; + bool dbar_flag = false; + bool sout_flag = false; + bool wave_flag = false; + // shape tags + bool shap_flag = false; + // family tags + bool faml_flag = false; + // size tags + bool size_flag = false; Layout const & style = *d->layout_; - xs.startParagraph(allowEmpty()); - - if (!runparams.for_toc && runparams.html_make_pars) { - // generate a magic label for this paragraph - string const attr = "id='" + magicLabel() + "'"; - xs << html::CompTag("a", attr); - } + if (start_paragraph) + xs.startDivision(allowEmpty()); FontInfo font_old = style.labeltype == LABEL_MANUAL ? style.labelfont : style.font; + FontShape curr_fs = INHERIT_SHAPE; + FontFamily curr_fam = INHERIT_FAMILY; + FontSize curr_size = FONT_SIZE_INHERIT; + + string const default_family = + buf.masterBuffer()->params().fonts_default_family; + + vector tagsToOpen; + vector tagsToClose; + // parsing main loop for (pos_type i = initial; i < size(); ++i) { // let's not show deleted material in the output if (isDeleted(i)) continue; - Font font = getFont(buf.params(), i, outerfont); + Font const font = getFont(buf.masterBuffer()->params(), i, outerfont); // emphasis - if (font_old.emph() != font.fontInfo().emph()) { - if (font.fontInfo().emph() == FONT_ON) { - xs << html::StartTag("em"); - emph_flag = true; - } else if (emph_flag && i != initial) { - xs << html::EndTag("em"); - emph_flag = false; + FontState curstate = font.fontInfo().emph(); + if (font_old.emph() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, emph_flag, curstate, html::FT_EMPH); + + // noun + curstate = font.fontInfo().noun(); + if (font_old.noun() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, noun_flag, curstate, html::FT_NOUN); + + // underbar + curstate = font.fontInfo().underbar(); + if (font_old.underbar() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, ubar_flag, curstate, html::FT_UBAR); + + // strikeout + curstate = font.fontInfo().strikeout(); + if (font_old.strikeout() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, sout_flag, curstate, html::FT_SOUT); + + // double underbar + curstate = font.fontInfo().uuline(); + if (font_old.uuline() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, dbar_flag, curstate, html::FT_DBAR); + + // wavy line + curstate = font.fontInfo().uwave(); + if (font_old.uwave() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, wave_flag, curstate, html::FT_WAVE); + + // bold + // a little hackish, but allows us to reuse what we have. + curstate = (font.fontInfo().series() == BOLD_SERIES ? FONT_ON : FONT_OFF); + if (font_old.series() != font.fontInfo().series()) + doFontSwitch(tagsToOpen, tagsToClose, bold_flag, curstate, html::FT_BOLD); + + // Font shape + curr_fs = font.fontInfo().shape(); + FontShape old_fs = font_old.shape(); + if (old_fs != curr_fs) { + if (shap_flag) { + switch (old_fs) { + case ITALIC_SHAPE: + tagsToClose.push_back(html::EndFontTag(html::FT_ITALIC)); + break; + case SLANTED_SHAPE: + tagsToClose.push_back(html::EndFontTag(html::FT_SLANTED)); + break; + case SMALLCAPS_SHAPE: + tagsToClose.push_back(html::EndFontTag(html::FT_SMALLCAPS)); + break; + case UP_SHAPE: + case INHERIT_SHAPE: + break; + default: + // the other tags are for internal use + LATTEST(false); + break; + } + shap_flag = false; + } + switch (curr_fs) { + case ITALIC_SHAPE: + tagsToOpen.push_back(html::FontTag(html::FT_ITALIC)); + shap_flag = true; + break; + case SLANTED_SHAPE: + tagsToOpen.push_back(html::FontTag(html::FT_SLANTED)); + shap_flag = true; + break; + case SMALLCAPS_SHAPE: + tagsToOpen.push_back(html::FontTag(html::FT_SMALLCAPS)); + shap_flag = true; + break; + case UP_SHAPE: + case INHERIT_SHAPE: + break; + default: + // the other tags are for internal use + LATTEST(false); + break; } } - // bold - if (font_old.series() != font.fontInfo().series()) { - if (font.fontInfo().series() == BOLD_SERIES) { - xs << html::StartTag("strong"); - bold_flag = true; - } else if (bold_flag && i != initial) { - xs << html::EndTag("strong"); - bold_flag = false; + + // Font family + curr_fam = font.fontInfo().family(); + FontFamily old_fam = font_old.family(); + if (old_fam != curr_fam) { + if (faml_flag) { + switch (old_fam) { + case ROMAN_FAMILY: + tagsToClose.push_back(html::EndFontTag(html::FT_ROMAN)); + break; + case SANS_FAMILY: + tagsToClose.push_back(html::EndFontTag(html::FT_SANS)); + break; + case TYPEWRITER_FAMILY: + tagsToClose.push_back(html::EndFontTag(html::FT_TYPE)); + break; + case INHERIT_FAMILY: + break; + default: + // the other tags are for internal use + LATTEST(false); + break; + } + faml_flag = false; + } + switch (curr_fam) { + case ROMAN_FAMILY: + // we will treat a "default" font family as roman, since we have + // no other idea what to do. + if (default_family != "rmdefault" && default_family != "default") { + tagsToOpen.push_back(html::FontTag(html::FT_ROMAN)); + faml_flag = true; + } + break; + case SANS_FAMILY: + if (default_family != "sfdefault") { + tagsToOpen.push_back(html::FontTag(html::FT_SANS)); + faml_flag = true; + } + break; + case TYPEWRITER_FAMILY: + if (default_family != "ttdefault") { + tagsToOpen.push_back(html::FontTag(html::FT_TYPE)); + faml_flag = true; + } + break; + case INHERIT_FAMILY: + break; + default: + // the other tags are for internal use + LATTEST(false); + break; + } + } + + // Font size + curr_size = font.fontInfo().size(); + FontSize old_size = font_old.size(); + if (old_size != curr_size) { + if (size_flag) { + switch (old_size) { + case FONT_SIZE_TINY: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_TINY)); + break; + case FONT_SIZE_SCRIPT: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_SCRIPT)); + break; + case FONT_SIZE_FOOTNOTE: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_FOOTNOTE)); + break; + case FONT_SIZE_SMALL: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_SMALL)); + break; + case FONT_SIZE_LARGE: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_LARGE)); + break; + case FONT_SIZE_LARGER: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_LARGER)); + break; + case FONT_SIZE_LARGEST: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_LARGEST)); + break; + case FONT_SIZE_HUGE: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_HUGE)); + break; + case FONT_SIZE_HUGER: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_HUGER)); + break; + case FONT_SIZE_INCREASE: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_INCREASE)); + break; + case FONT_SIZE_DECREASE: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_DECREASE)); + break; + case FONT_SIZE_INHERIT: + case FONT_SIZE_NORMAL: + break; + default: + // the other tags are for internal use + LATTEST(false); + break; + } + size_flag = false; + } + switch (curr_size) { + case FONT_SIZE_TINY: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_TINY)); + size_flag = true; + break; + case FONT_SIZE_SCRIPT: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_SCRIPT)); + size_flag = true; + break; + case FONT_SIZE_FOOTNOTE: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_FOOTNOTE)); + size_flag = true; + break; + case FONT_SIZE_SMALL: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_SMALL)); + size_flag = true; + break; + case FONT_SIZE_LARGE: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_LARGE)); + size_flag = true; + break; + case FONT_SIZE_LARGER: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_LARGER)); + size_flag = true; + break; + case FONT_SIZE_LARGEST: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_LARGEST)); + size_flag = true; + break; + case FONT_SIZE_HUGE: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_HUGE)); + size_flag = true; + break; + case FONT_SIZE_HUGER: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_HUGER)); + size_flag = true; + break; + case FONT_SIZE_INCREASE: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_INCREASE)); + size_flag = true; + break; + case FONT_SIZE_DECREASE: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_DECREASE)); + size_flag = true; + break; + case FONT_SIZE_NORMAL: + case FONT_SIZE_INHERIT: + break; + default: + // the other tags are for internal use + LATTEST(false); + break; } } + // FIXME XHTML // Other such tags? What about the other text ranges? + vector::const_iterator cit = tagsToClose.begin(); + vector::const_iterator cen = tagsToClose.end(); + for (; cit != cen; ++cit) + xs << *cit; + + vector::const_iterator sit = tagsToOpen.begin(); + vector::const_iterator sen = tagsToOpen.end(); + for (; sit != sen; ++sit) + xs << *sit; + + tagsToClose.clear(); + tagsToOpen.clear(); + Inset const * inset = getInset(i); if (inset) { if (!runparams.for_toc || inset->isInToc()) { OutputParams np = runparams; - if (!inset->getLayout().htmlisblock()) + np.local_font = &font; + // If the paragraph has size 1, then we are in the "special + // case" where we do not output the containing paragraph info + if (!inset->getLayout().htmlisblock() && size() != 1) np.html_in_par = true; retval += inset->xhtml(xs, np); } } else { - char_type c = getUChar(buf.params(), i); - - if (style.pass_thru || runparams.pass_thru) - xs << c; - else if (c == '-') { - docstring str; - int j = i + 1; - if (j < size() && d->text_[j] == '-') { - j += 1; - if (j < size() && d->text_[j] == '-') { - str += from_ascii("—"); - i += 2; - } else { - str += from_ascii("–"); - i += 1; - } - } - else - str += c; - // We don't want to escape the entities. Note that - // it is safe to do this, since str can otherwise - // only be "-". E.g., it can't be "<". - xs << XHTMLStream::ESCAPE_NONE << str; - } else - xs << c; + char_type c = getUChar(buf.masterBuffer()->params(), i); + xs << c; } font_old = font.fontInfo(); } + // FIXME 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.endParagraph(); + if (close_paragraph) + xs.endDivision(); + return retval; } @@ -2932,8 +3093,7 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf, bool Paragraph::isHfill(pos_type pos) const { Inset const * inset = getInset(pos); - return inset && (inset->lyxCode() == SPACE_CODE && - inset->isStretchableSpace()); + return inset && inset->isHfill(); } @@ -2944,6 +3104,13 @@ bool Paragraph::isNewline(pos_type pos) const } +bool Paragraph::isEnvSeparator(pos_type pos) const +{ + Inset const * inset = getInset(pos); + return inset && inset->lyxCode() == SEPARATOR_CODE; +} + + bool Paragraph::isLineSeparator(pos_type pos) const { char_type const c = d->text_[pos]; @@ -2987,16 +3154,13 @@ bool Paragraph::isHardHyphenOrApostrophe(pos_type pos) const if ((nextpos == psize || isSpace(nextpos)) && (pos == 0 || isSpace(prevpos))) return false; - return c == '\'' - || ((nextpos == psize || d->text_[nextpos] != '-') - && (pos == 0 || d->text_[prevpos] != '-')); + return true; } -bool Paragraph::isSameSpellRange(pos_type pos1, pos_type pos2) const +FontSpan const & Paragraph::getSpellRange(pos_type pos) const { - return pos1 == pos2 - || d->speller_state_.getRange(pos1) == d->speller_state_.getRange(pos2); + return d->speller_state_.getRange(pos); } @@ -3030,8 +3194,7 @@ Paragraph::getParLanguage(BufferParams const & bparams) const bool Paragraph::isRTL(BufferParams const & bparams) const { - return lyxrc.rtl_support - && getParLanguage(bparams)->rightToLeft() + return getParLanguage(bparams)->rightToLeft() && !inInset().getLayout().forceLTR(); } @@ -3086,7 +3249,7 @@ docstring Paragraph::asString(int options) const } -docstring Paragraph::asString(pos_type beg, pos_type end, int options) const +docstring Paragraph::asString(pos_type beg, pos_type end, int options, const OutputParams *runparams) const { odocstringstream os; @@ -3103,9 +3266,12 @@ docstring Paragraph::asString(pos_type beg, pos_type end, int options) const || (c == '\n' && (options & AS_STR_NEWLINES))) os.put(c); else if (c == META_INSET && (options & AS_STR_INSETS)) { - getInset(i)->toString(os); - if (getInset(i)->asInsetMath()) - os << " "; + if (c == META_INSET && (options & AS_STR_PLAINTEXT)) { + LASSERT(runparams != 0, return docstring()); + getInset(i)->plaintext(os, *runparams); + } else { + getInset(i)->toString(os); + } } } @@ -3113,44 +3279,23 @@ docstring Paragraph::asString(pos_type beg, pos_type end, int options) const } -void Paragraph::forToc(docstring & os, size_t maxlen) const +void Paragraph::forOutliner(docstring & os, size_t const maxlen, + bool const shorten) const { + size_t tmplen = shorten ? maxlen + 1 : maxlen; if (!d->params_.labelString().empty()) os += d->params_.labelString() + ' '; - for (pos_type i = 0; i < size() && os.length() < maxlen; ++i) { + for (pos_type i = 0; i < size() && os.length() < tmplen; ++i) { if (isDeleted(i)) continue; char_type const c = d->text_[i]; if (isPrintable(c)) os += c; - else if (c == '\t' || c == '\n') - os += ' '; else if (c == META_INSET) - getInset(i)->forToc(os, maxlen); - } -} - - -docstring Paragraph::stringify(pos_type beg, pos_type end, int options, OutputParams & runparams) const -{ - odocstringstream os; - - if (beg == 0 - && options & AS_STR_LABEL - && !d->params_.labelString().empty()) - os << d->params_.labelString() << ' '; - - for (pos_type i = beg; i < end; ++i) { - char_type const c = d->text_[i]; - if (isPrintable(c) || c == '\t' - || (c == '\n' && (options & AS_STR_NEWLINES))) - os.put(c); - else if (c == META_INSET && (options & AS_STR_INSETS)) { - getInset(i)->plaintext(os, runparams); - } + getInset(i)->forOutliner(os, tmplen, false); } - - return os.str(); + if (shorten) + Text::shortenForOutliner(os, maxlen); } @@ -3207,8 +3352,7 @@ void Paragraph::setPlainOrDefaultLayout(DocumentClass const & tclass) Inset const & Paragraph::inInset() const { - LASSERT(d->inset_owner_, throw ExceptionMessage(BufferException, - _("Memory problem"), _("Paragraph not properly initialized"))); + LBUFERR(d->inset_owner_); return *d->inset_owner_; } @@ -3241,46 +3385,6 @@ bool Paragraph::allowEmpty() const } -char_type Paragraph::transformChar(char_type c, pos_type pos) const -{ - if (!Encodings::isArabicChar(c)) - return c; - - char_type prev_char = ' '; - char_type next_char = ' '; - - for (pos_type i = pos - 1; i >= 0; --i) { - char_type const par_char = d->text_[i]; - if (!Encodings::isArabicComposeChar(par_char)) { - prev_char = par_char; - break; - } - } - - for (pos_type i = pos + 1, end = size(); i < end; ++i) { - char_type const par_char = d->text_[i]; - if (!Encodings::isArabicComposeChar(par_char)) { - next_char = par_char; - break; - } - } - - if (Encodings::isArabicChar(next_char)) { - if (Encodings::isArabicChar(prev_char) && - !Encodings::isArabicSpecialChar(prev_char)) - return Encodings::transformChar(c, Encodings::FORM_MEDIAL); - else - return Encodings::transformChar(c, Encodings::FORM_INITIAL); - } else { - if (Encodings::isArabicChar(prev_char) && - !Encodings::isArabicSpecialChar(prev_char)) - return Encodings::transformChar(c, Encodings::FORM_FINAL); - else - return Encodings::transformChar(c, Encodings::FORM_ISOLATED); - } -} - - bool Paragraph::brokenBiblio() const { // there is a problem if there is no bibitem at position 0 or @@ -3302,7 +3406,7 @@ int Paragraph::fixBiblio(Buffer const & buffer) if (d->layout_->labeltype != LABEL_BIBLIO) return 0; - bool const track_changes = buffer.params().trackChanges; + bool const track_changes = buffer.params().track_changes; int bibitem_pos = d->insetlist_.find(BIBITEM_CODE); bool const hasbibitem0 = bibitem_pos == 0; @@ -3317,8 +3421,7 @@ int Paragraph::fixBiblio(Buffer const & buffer) // these, which there should be. // FIXME: why does it make sense to do that rather // than keep the first? (JMarc) - Inset * inset = d->insetlist_.release(bibitem_pos); - eraseChar(bibitem_pos, track_changes); + Inset * inset = releaseInset(bibitem_pos); d->insetlist_.begin()->inset = inset; return -bibitem_pos; } @@ -3334,7 +3437,8 @@ int Paragraph::fixBiblio(Buffer const & buffer) inset = new InsetBibitem(const_cast(&buffer), InsetCommandParams(BIBITEM_CODE)); - insertInset(0, inset, Change(track_changes ? Change::INSERTED + Font font(inherit_font, buffer.params().language); + insertInset(0, inset, font, Change(track_changes ? Change::INSERTED : Change::UNCHANGED)); return 1; @@ -3406,9 +3510,11 @@ void Paragraph::changeCase(BufferParams const & bparams, pos_type pos, // process sequences of modified characters; in change // tracking mode, this approach results in much better // usability than changing case on a char-by-char basis - docstring changes; + // We also need to track the current font, since font + // changes within sequences can occur. + vector > changes; - bool const trackChanges = bparams.trackChanges; + bool const trackChanges = bparams.track_changes; bool capitalize = true; @@ -3440,7 +3546,7 @@ void Paragraph::changeCase(BufferParams const & bparams, pos_type pos, } if (oldChar != newChar) { - changes += newChar; + changes.push_back(make_pair(newChar, getFontSettings(bparams, pos))); if (pos != right - 1) continue; // step behind the changing area @@ -3449,9 +3555,8 @@ void Paragraph::changeCase(BufferParams const & bparams, pos_type pos, int erasePos = pos - changes.size(); for (size_t i = 0; i < changes.size(); i++) { - insertChar(pos, changes[i], - getFontSettings(bparams, - erasePos), + insertChar(pos, changes[i].first, + changes[i].second, trackChanges); if (!eraseChar(erasePos, trackChanges)) { ++erasePos; @@ -3590,20 +3695,28 @@ void Paragraph::locateWord(pos_type & from, pos_type & to, void Paragraph::collectWords() { - pos_type n = size(); - for (pos_type pos = 0; pos < n; ++pos) { + for (pos_type pos = 0; pos < size(); ++pos) { if (isWordSeparator(pos)) continue; pos_type from = pos; locateWord(from, pos, WHOLE_WORD); - if ((pos - from) >= (int)lyxrc.completion_minlength) { - docstring word = asString(from, pos, AS_STR_NONE); - FontList::const_iterator cit = d->fontlist_.fontIterator(pos); - if (cit == d->fontlist_.end()) - return; - Language const * lang = cit->font().language(); - d->words_[*lang].insert(word); - } + // Work around MSVC warning: The statement + // if (pos < from + lyxrc.completion_minlength) + // triggers a signed vs. unsigned warning. + // I don't know why this happens, it could be a MSVC bug, or + // related to LLP64 (windows) vs. LP64 (unix) programming + // model, or the C++ standard might be ambigous in the section + // defining the "usual arithmetic conversions". However, using + // a temporary variable is safe and works on all compilers. + pos_type const endpos = from + lyxrc.completion_minlength; + if (pos < endpos) + continue; + FontList::const_iterator cit = d->fontlist_.fontIterator(from); + if (cit == d->fontlist_.end()) + return; + Language const * lang = cit->font().language(); + docstring const word = asString(from, pos, AS_STR_NONE); + d->words_[lang->lang()].insert(word); } }