X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FParagraph.cpp;h=a6d61e6000797c2557667c0dd8559df0ca8f6816;hb=7af6575cf6cd764b8b567b358907ac9a7a8e322b;hp=27aecb5eaee7fc4af6a211e6617136b572ed97a4;hpb=68b6198d635e2448c89c3f85caf146fd72951f8c;p=lyx.git diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 27aecb5eae..a6d61e6000 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -329,15 +329,6 @@ public: Font const & font, Layout const & style); - /// Output consecutive unicode chars, belonging to the same script as - /// specified by the latex macro \p ltx, to \p os starting from \p i. - /// \return the number of characters written. - int writeScriptChars(BufferParams const &, OutputParams const &, - otexstream & os, - docstring const & ltx, - Change const &, Encoding const &, - std::string const, pos_type & i); - /// This could go to ParagraphParameters if we want to. int startTeXParParams(BufferParams const &, otexstream &, OutputParams const &) const; @@ -365,7 +356,7 @@ public: BufferParams const & bparams, OutputParams const & runparams, Font const & running_font, - Change const & running_change, + string & alien_script, Layout const & style, pos_type & i, pos_type end_pos, @@ -454,10 +445,10 @@ public: return; } pos_type endpos = last; - owner_->locateWord(first, endpos, WHOLE_WORD); + owner_->locateWord(first, endpos, WHOLE_WORD, true); if (endpos < last) { endpos = last; - owner_->locateWord(last, endpos, WHOLE_WORD); + owner_->locateWord(last, endpos, WHOLE_WORD, true); } last = endpos; } @@ -525,7 +516,7 @@ public: Paragraph::Private::Private(Paragraph * owner, Layout const & layout) - : owner_(owner), inset_owner_(0), id_(-1), begin_of_body_(0), layout_(&layout) + : owner_(owner), inset_owner_(nullptr), id_(-1), begin_of_body_(0), layout_(&layout) { text_.reserve(100); } @@ -590,18 +581,6 @@ void Paragraph::addChangesToToc(DocIterator const & cdit, Buffer const & buf, } -void Paragraph::addChangesToBuffer(Buffer const & buf) const -{ - d->changes_.updateBuffer(buf); -} - - -bool Paragraph::isChangeUpdateRequired() const -{ - return d->changes_.isUpdateRequired(); -} - - bool Paragraph::isDeleted(pos_type start, pos_type end) const { LASSERT(start >= 0 && start <= size(), return false); @@ -619,6 +598,28 @@ bool Paragraph::isChanged(pos_type start, pos_type end) const return d->changes_.isChanged(start, end); } +// FIXME: Ideally the diverse isChanged() methods should account for that! +bool Paragraph::hasChangedInsets(pos_type start, pos_type end) const +{ + LASSERT(start >= 0 && start <= size(), return false); + LASSERT(end > start && end <= size() + 1, return false); + + for (auto const & icit : d->insetlist_) { + if (icit.pos < start) + continue; + if (icit.pos >= end) + break; + if (icit.inset && icit.inset->isChanged()) + return true; + } + return false; +} + +bool Paragraph::isChanged() const +{ + return d->changes_.isChanged(); +} + bool Paragraph::isMergedOnEndOfParDeletion(bool trackChanges) const { @@ -630,6 +631,11 @@ bool Paragraph::isMergedOnEndOfParDeletion(bool trackChanges) const return change.inserted() && change.currentAuthor(); } +Change Paragraph::parEndChange() const +{ + return d->changes_.lookup(size()); +} + void Paragraph::setChange(Change const & change) { @@ -664,8 +670,8 @@ void Paragraph::setChange(pos_type pos, Change const & change) // see comment in setChange(Change const &) above if (!change.deleted() && pos < size()) - if (Inset * inset = getInset(pos)) - inset->setChange(change); + if (Inset * inset = getInset(pos)) + inset->setChange(change); } @@ -891,47 +897,15 @@ int Paragraph::Private::latexSurrogatePair(BufferParams const & bparams, } docstring latex2 = encoding.latexChar(c).first; - // Handle combining characters in "script" context (i.e., \textgreek and \textcyrillic) - docstring::size_type const brace1 = latex2.find_first_of(from_ascii("{")); - docstring::size_type const brace2 = latex2.find_last_of(from_ascii("}")); - string script = to_ascii(latex2.substr(1, brace1 - 1)); - - // Greek and Cyrillic letters need to be wrapped in \textcyrillic and \textgreek if they - // are not encodable in the current font encoding (regardless of the input encoding). - bool scriptchar = false; - if (!bparams.useNonTeXFonts) // With non-TeX fonts the font encoding is Unicode. - scriptchar = Encodings::isKnownScriptChar(c, script); - - if (!scriptchar && docstring(1, next) == latex1) { - // Font and input encoding support the combination: + if (bparams.useNonTeXFonts || docstring(1, next) == latex1) { + // Encoding supports the combination: // output as is (combining char after base char). os << latex2 << latex1; return latex1.length() + latex2.length(); } - int pos = 0; - int length = brace2; - string fontenc; - if (runparams.local_font) - fontenc = runparams.local_font->language()->fontenc(bparams); - else - fontenc = bparams.language->fontenc(bparams); - docstring scriptmacro; - docstring cb; - if (script == "textgreek" || script == "textcyrillic") { - // Strip the \text(greek|cyrillic) script macro ... - pos = brace1 + 1; - length -= pos; - latex2 = latex2.substr(pos, length); - // and place it before the accent macro if required (#6463) - if (Encodings::needsScriptWrapper(script, fontenc)) { - scriptmacro = from_ascii("\\" + script + "{"); - cb = from_ascii("}"); - } - } - - os << scriptmacro << latex1 << "{" << latex2 << "}" << cb; - return latex1.length() + 1 + latex2.length() + 1 + cb.length(); + os << latex1 << "{" << latex2 << "}"; + return latex1.length() + latex2.length() + 2; } @@ -981,94 +955,6 @@ bool Paragraph::Private::simpleTeXBlanks(BufferParams const & bparams, } -int Paragraph::Private::writeScriptChars(BufferParams const & bparams, - OutputParams const & runparams, - otexstream & os, - docstring const & ltx, - Change const & runningChange, - Encoding const & encoding, - string const fontenc, - pos_type & i) -{ - // FIXME: modifying i here is not very nice... - - // 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. - // 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] - // belongs and we use it in order to check whether characters from the - // same script immediately follow, such that we can collect them in a - // single "\textXXX" macro. So, we have to retain "\textXXX{" - // for the first char but only "" for all subsequent chars. - docstring::size_type const brace1 = ltx.find_first_of(from_ascii("{")); - docstring::size_type const brace2 = ltx.find_last_of(from_ascii("}")); - string script = to_ascii(ltx.substr(1, brace1 - 1)); - int pos = 0; - int length = brace2; - bool closing_brace = true; - // We only need the script macro with non-native font encodings - if (!Encodings::needsScriptWrapper(script, fontenc)) { - // Correct font encoding is being used, so we can avoid \text(greek|cyrrillic). - pos = brace1 + 1; - length -= pos; - closing_brace = false; - } - os << ltx.substr(pos, length); - int size = text_.size(); - while (i + 1 < size) { - char_type const next = text_[i + 1]; - // Stop here if next character belongs to another script - // or there is a change in change tracking status. - if (!Encodings::isKnownScriptChar(next, script) || - runningChange != owner_->lookupChange(i + 1)) - break; - Font prev_font; - bool found = false; - FontList::const_iterator cit = fontlist_.begin(); - FontList::const_iterator end = fontlist_.end(); - for (; cit != end; ++cit) { - if (cit->pos() >= i && !found) { - prev_font = cit->font(); - found = true; - } - if (cit->pos() >= i + 1) - break; - } - // Stop here if there is a font attribute or encoding change. - if (found && cit != end && prev_font != cit->font()) - break; - - // Check whether we have a combining pair - char_type next_next = '\0'; - if (i + 2 < size) { - next_next = text_[i + 2]; - if (Encodings::isCombiningChar(next_next)) { - length += latexSurrogatePair(bparams, os, next, next_next, runparams) - 1; - i += 2; - continue; - } - } - - docstring const latex = encoding.latexChar(next).first; - docstring::size_type const b1 = - latex.find_first_of(from_ascii("{")); - docstring::size_type const b2 = - latex.find_last_of(from_ascii("}")); - int const len = b2 - b1 - 1; - os << latex.substr(b1 + 1, len); - length += len; - ++i; - } - if (closing_brace) { - os << '}'; - ++length; - } - return length; -} - - void Paragraph::Private::latexInset(BufferParams const & bparams, otexstream & os, OutputParams & runparams, @@ -1134,7 +1020,7 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, bool close = false; odocstream::pos_type const len = os.os().tellp(); - if (inset->forceLTR() + if (inset->forceLTR(runparams) && running_font.isRightToLeft() // ERT is an exception, it should be output with no // decorations at all @@ -1218,7 +1104,7 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, BufferParams const & bparams, OutputParams const & runparams, Font const & running_font, - Change const & running_change, + string & alien_script, Layout const & style, pos_type & i, pos_type end_pos, @@ -1250,7 +1136,7 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, && !runparams.isFullUnicode() && bparams.main_font_encoding() == "T1" && latexSpecialT1(c, os, i, column)) return; - // NOTE: XeTeX and LuaTeX use EU1/2 (pre 2017) or TU (as of 2017) encoding + // NOTE: "fontspec" (non-TeX fonts) sets the font encoding to "TU" (untill 2017 "EU1" or "EU2") else if (!runparams.inIPA && !running_font.language()->internalFontEncoding() && runparams.isFullUnicode() && latexSpecialTU(c, os, i, column)) return; @@ -1360,12 +1246,11 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, break; } } - string script; pair latex = encoding.latexChar(c); docstring nextlatex; bool nexttipas = false; string nexttipashortcut; - if (next != '\0' && next != META_INSET && encoding.encodable(next)) { + if (next != '\0' && next != META_INSET && !encoding.encodable(next)) { nextlatex = encoding.latexChar(next).first; if (runparams.inIPA) { nexttipashortcut = Encodings::TIPAShortcut(next); @@ -1381,27 +1266,22 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, tipas = true; } } - string fontenc; - fontenc = running_font.language()->fontenc(bparams); - // "Script chars" need to embraced in \textcyrillic and \textgreek notwithstanding - // whether they are encodable or not (it only depends on the font encoding), - // except if we are using fontspec. - if (!bparams.useNonTeXFonts && Encodings::isKnownScriptChar(c, script)) { - docstring const wrapper = from_ascii("\\" + script + "{"); - docstring ltx = latex.first; - if (!prefixIs(ltx, wrapper)) - ltx = wrapper + latex.first + from_ascii("}"); - column += writeScriptChars(bparams, runparams, os, ltx, running_change, - encoding, fontenc, i) - 1; - } else if (latex.second + // eventually close "script wrapper" command (see `Paragraph::latex`) + if (!alien_script.empty() + && alien_script != Encodings::isKnownScriptChar(next)) { + column += latex.first.length(); + alien_script.clear(); + os << latex.first << "}"; + break; + } + if (latex.second && ((!prefixIs(nextlatex, '\\') && !prefixIs(nextlatex, '{') && !prefixIs(nextlatex, '}')) || (nexttipas && !prefixIs(from_ascii(nexttipashortcut), '\\'))) && !tipas) { - // Prevent eating of a following - // space or command corruption by + // Prevent eating of a following space or command corruption by // following characters if (next == ' ' || next == '\0') { column += latex.first.length() + 1; @@ -1486,7 +1366,8 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const otexstringstream os; os << layout_->preamble(); size_t const length = os.length(); - TeXOnePar(buf, buf.text(), buf.getParFromID(owner_->id()).pit(), os, + TeXOnePar(buf, *inset_owner_->getText(int(buf.getParFromID(owner_->id()).idx())), + buf.getParFromID(owner_->id()).pit(), os, features.runparams(), string(), 0, -1, true); if (os.length() > length) features.addPreambleSnippet(os.release(), true); @@ -1781,6 +1662,8 @@ void Paragraph::validate(LaTeXFeatures & features) const d->validate(features); bool fragile = features.runparams().moving_arg; fragile |= layout().needprotect; + if (inInset().getLayout().isNeedProtect()) + fragile = true; if (needsCProtection(fragile)) features.require("cprotect"); } @@ -1881,7 +1764,7 @@ Font const & Paragraph::getFontSettings(BufferParams const & bparams, // Optimisation: avoid a full font instantiation if there is no // language change from previous call. static Font previous_font; - static Language const * previous_lang = 0; + static Language const * previous_lang = nullptr; Language const * lang = getParLanguage(bparams); if (lang != previous_lang) { previous_lang = lang; @@ -1929,7 +1812,7 @@ Font const & Paragraph::getFirstFontSettings(BufferParams const & bparams) const // Optimisation: avoid a full font instantiation if there is no // language change from previous call. static Font previous_font; - static Language const * previous_lang = 0; + static Language const * previous_lang = nullptr; if (bparams.language != previous_lang) { previous_lang = bparams.language; previous_font = Font(inherit_font, bparams.language); @@ -1992,8 +1875,9 @@ char_type Paragraph::getUChar(BufferParams const & bparams, char_type c = d->text_[pos]; // Return unchanged character in LTR languages - // or if we use poylglossia/bidi. - if (rp.use_polyglossia || !getFontSettings(bparams, pos).isRightToLeft()) + // or if we use poylglossia/bidi (XeTeX). + if (rp.useBidiPackage() + || !getFontSettings(bparams, pos).isRightToLeft()) return c; // Without polyglossia/bidi, we need to account for some special cases. @@ -2012,7 +1896,8 @@ char_type Paragraph::getUChar(BufferParams const & bparams, char_type uc = c; // 1. In the following languages, parentheses need to be reversed. - bool const reverseparens = lang == "hebrew"; + // Also with polyglodia/luabidi + bool const reverseparens = (lang == "hebrew" || rp.use_polyglossia); // 2. In the following languages, brackets don't need to be reversed. bool const reversebrackets = lang != "arabic_arabtex" @@ -2115,15 +2000,29 @@ depth_type Paragraph::getMaxDepthAfter() const } -LyXAlignment Paragraph::getAlign() const +LyXAlignment Paragraph::getAlign(BufferParams const & bparams) const { if (d->params_.align() == LYX_ALIGN_LAYOUT) - return d->layout_->align; + return getDefaultAlign(bparams); else return d->params_.align(); } +LyXAlignment Paragraph::getDefaultAlign(BufferParams const & bparams) const +{ + LyXAlignment res = layout().align; + if (isRTL(bparams)) { + // Swap sides + if (res == LYX_ALIGN_LEFT) + res = LYX_ALIGN_RIGHT; + else if (res == LYX_ALIGN_RIGHT) + res = LYX_ALIGN_LEFT; + } + return res; +} + + docstring const & Paragraph::labelString() const { return d->params_.labelString(); @@ -2223,15 +2122,17 @@ void Paragraph::setBeginOfBody() // remove unnecessary getChar() calls pos_type i = 0; pos_type end = size(); - if (i < end && !(isNewline(i) || isEnvSeparator(i))) { + bool prev_char_deleted = false; + if (i < end && (!(isNewline(i) || isEnvSeparator(i)) || isDeleted(i))) { ++i; if (i < end) { char_type previous_char = d->text_[i]; if (!(isNewline(i) || isEnvSeparator(i))) { ++i; - while (i < end && previous_char != ' ') { + while (i < end && (previous_char != ' ' || prev_char_deleted)) { char_type temp = d->text_[i]; - if (isNewline(i) || isEnvSeparator(i)) + prev_char_deleted = isDeleted(i); + if (!isDeleted(i) && (isNewline(i) || isEnvSeparator(i))) break; ++i; previous_char = temp; @@ -2363,8 +2264,9 @@ int Paragraph::Private::startTeXParParams(BufferParams const & bparams, InsetCode code = ownerCode(); bool const lastpar = runparams.isLastPar; // RTL in classic (PDF)LaTeX (without the Bidi package) + // Luabibdi (used by LuaTeX) behaves like classic bool const rtl_classic = owner_->getParLanguage(bparams)->rightToLeft() - && !runparams.use_polyglossia; + && !runparams.useBidiPackage(); switch (curAlign) { case LYX_ALIGN_NONE: @@ -2426,8 +2328,9 @@ bool Paragraph::Private::endTeXParParams(BufferParams const & bparams, InsetCode code = ownerCode(); bool const lastpar = runparams.isLastPar; // RTL in classic (PDF)LaTeX (without the Bidi package) + // Luabibdi (used by LuaTeX) behaves like classic bool const rtl_classic = owner_->getParLanguage(bparams)->rightToLeft() - && !runparams.use_polyglossia; + && !runparams.useBidiPackage(); switch (curAlign) { case LYX_ALIGN_NONE: @@ -2487,6 +2390,11 @@ void Paragraph::latex(BufferParams const & bparams, // of the body. Font basefont; + // If there is an open font-encoding changing command (script wrapper), + // alien_script is set to its name + string alien_script; + string script; + // Maybe we have to create a optional argument. pos_type body_pos = beginOfBody(); unsigned int column = 0; @@ -2581,9 +2489,14 @@ void Paragraph::latex(BufferParams const & bparams, Change const & change = runparams.inDeletedInset ? runparams.changeOfDeletedInset : lookupChange(i); + char_type const c = d->text_[i]; + // Check whether a display math inset follows - if (d->text_[i] == META_INSET + if (c == META_INSET && i >= start_pos && (end_pos == -1 || i < end_pos)) { + if (isDeleted(i)) + runparams.ctObject = getInset(i)->CtObject(runparams); + InsetMath const * im = getInset(i)->asInsetMath(); if (im && im->asHullInset() && im->asHullInset()->outerDisplay()) { @@ -2609,7 +2522,8 @@ void Paragraph::latex(BufferParams const & bparams, basefont, needPar); open_font = false; } - basefont = getLayoutFont(bparams, outerfont); + basefont = (body_pos > i) ? getLabelFont(bparams, outerfont) + : getLayoutFont(bparams, outerfont); running_font = basefont; column += Changes::latexMarkChange(os, bparams, Change(Change::INSERTED), change, rp); @@ -2617,6 +2531,11 @@ void Paragraph::latex(BufferParams const & bparams, } if (bparams.output_changes && runningChange != change) { + if (!alien_script.empty()) { + column += 1; + os << "}"; + alien_script.clear(); + } if (open_font) { bool needPar = false; column += running_font.latexWriteEndChanges( @@ -2624,7 +2543,8 @@ void Paragraph::latex(BufferParams const & bparams, basefont, basefont, needPar); open_font = false; } - basefont = getLayoutFont(bparams, outerfont); + basefont = (body_pos > i) ? getLabelFont(bparams, outerfont) + : getLayoutFont(bparams, outerfont); running_font = basefont; column += Changes::latexMarkChange(os, bparams, runningChange, change, runparams); @@ -2649,6 +2569,12 @@ void Paragraph::latex(BufferParams const & bparams, (current_font != running_font || current_font.language() != running_font.language())) { + // ensure there is no open script-wrapper + if (!alien_script.empty()) { + column += 1; + os << "}"; + alien_script.clear(); + } bool needPar = false; column += running_font.latexWriteEndChanges( os, bparams, runparams, basefont, @@ -2658,23 +2584,17 @@ void Paragraph::latex(BufferParams const & bparams, open_font = false; } - string const running_lang = runparams.use_polyglossia ? - running_font.language()->polyglossia() : running_font.language()->babel(); - // close babel's font environment before opening CJK. - string const lang_end_command = runparams.use_polyglossia ? - "\\end{$$lang}" : lyxrc.language_command_end; - bool const using_begin_end = runparams.use_polyglossia || - !lang_end_command.empty(); - if (!running_lang.empty() && - (!using_begin_end || running_lang == openLanguageName()) && - current_font.language()->encoding()->package() == Encoding::CJK) { - string end_tag = subst(lang_end_command, - "$$lang", - running_lang); - os << from_ascii(end_tag); - column += end_tag.length(); - if (using_begin_end) - popLanguageName(); + // if necessary, close language environment before opening CJK + string const running_lang = running_font.language()->babel(); + string const lang_end_command = lyxrc.language_command_end; + if (!lang_end_command.empty() && !bparams.useNonTeXFonts + && !running_lang.empty() + && running_lang == openLanguageName() + && current_font.language()->encoding()->package() == Encoding::CJK) { + string end_tag = subst(lang_end_command, "$$lang", running_lang); + os << from_ascii(end_tag); + column += end_tag.length(); + popLanguageName(); } // Switch file encoding if necessary (and allowed) @@ -2690,8 +2610,6 @@ void Paragraph::latex(BufferParams const & bparams, } } - char_type const c = d->text_[i]; - // A display math inset inside an ulem command will be output // as a box of width \linewidth, so we have to either disable // indentation if the inset starts a paragraph, or start a new @@ -2710,6 +2628,21 @@ void Paragraph::latex(BufferParams const & bparams, current_font.language() != running_font.language()) && i != body_pos - 1) { + bool const in_ct_deletion = (bparams.output_changes + && runningChange == change + && change.type == Change::DELETED + && !os.afterParbreak()); + if (in_ct_deletion) { + // We have to close and then reopen \lyxdeleted, + // as strikeout needs to be on lowest level. + bool needPar = false; + OutputParams rp = runparams; + column += running_font.latexWriteEndChanges( + os, bparams, rp, basefont, + basefont, needPar); + os << '}'; + column += 1; + } odocstringstream ods; column += current_font.latexWriteStartChanges(ods, bparams, runparams, basefont, @@ -2738,6 +2671,13 @@ void Paragraph::latex(BufferParams const & bparams, << from_ascii("{}"); else os << fontchange; + if (in_ct_deletion) { + // We have to close and then reopen \lyxdeleted, + // as strikeout needs to be on lowest level. + OutputParams rp = runparams; + column += Changes::latexMarkChange(os, bparams, + Change(Change::UNCHANGED), change, rp); + } } // FIXME: think about end_pos implementation... @@ -2779,7 +2719,7 @@ void Paragraph::latex(BufferParams const & bparams, Inset const * inset = getInset(i); InsetText const * textinset = inset ? inset->asInsetText() - : 0; + : nullptr; if (i + 1 == size() && textinset && !inset->getLayout().isDisplay()) { ParagraphList const & pars = @@ -2804,12 +2744,36 @@ void Paragraph::latex(BufferParams const & bparams, runningChange, style, i, column); if (incremented) --parInline; + + if (runparams.ctObject == OutputParams::CT_DISPLAYOBJECT + || runparams.ctObject == OutputParams::CT_UDISPLAYOBJECT) { + // Close \lyx*deleted and force its + // reopening (if needed) + os << '}'; + column++; + runningChange = Change(Change::UNCHANGED); + runparams.ctObject = OutputParams::CT_NORMAL; + } } } else if (i >= start_pos && (end_pos == -1 || i < end_pos)) { + if (!bparams.useNonTeXFonts) + script = Encodings::isKnownScriptChar(c); + if (script != alien_script) { + if (!alien_script.empty()) { + os << "}"; + alien_script.clear(); + } + string fontenc = running_font.language()->fontenc(bparams); + if (!script.empty() + && !Encodings::fontencSupportsScript(fontenc, script)) { + column += script.length() + 2; + os << "\\" << script << "{"; + alien_script = script; + } + } try { - d->latexSpecialChar(os, bparams, rp, - running_font, runningChange, - style, i, end_pos, column); + d->latexSpecialChar(os, bparams, rp, running_font, + alien_script, style, i, end_pos, column); } catch (EncodingException & e) { if (runparams.dryrun) { os << "<" << _("LyX Warning: ") @@ -2833,6 +2797,15 @@ void Paragraph::latex(BufferParams const & bparams, // such as Note that do not produce any output, so that no // command is ever executed but its opening was recorded. runparams.inulemcmd = rp.inulemcmd; + + // And finally, pass the post_macros upstream + runparams.post_macro = rp.post_macro; + } + + // Close wrapper for alien script + if (!alien_script.empty()) { + os << "}"; + alien_script.clear(); } // If we have an open font definition, we have to close it @@ -3119,7 +3092,7 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf, FontShape curr_fs = INHERIT_SHAPE; FontFamily curr_fam = INHERIT_FAMILY; - FontSize curr_size = FONT_SIZE_INHERIT; + FontSize curr_size = INHERIT_SIZE; string const default_family = buf.masterBuffer()->params().fonts_default_family; @@ -3284,41 +3257,41 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf, if (old_size != curr_size) { if (size_flag) { switch (old_size) { - case FONT_SIZE_TINY: + case TINY_SIZE: tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_TINY)); break; - case FONT_SIZE_SCRIPT: + case SCRIPT_SIZE: tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_SCRIPT)); break; - case FONT_SIZE_FOOTNOTE: + case FOOTNOTE_SIZE: tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_FOOTNOTE)); break; - case FONT_SIZE_SMALL: + case SMALL_SIZE: tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_SMALL)); break; - case FONT_SIZE_LARGE: + case LARGE_SIZE: tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_LARGE)); break; - case FONT_SIZE_LARGER: + case LARGER_SIZE: tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_LARGER)); break; - case FONT_SIZE_LARGEST: + case LARGEST_SIZE: tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_LARGEST)); break; - case FONT_SIZE_HUGE: + case HUGE_SIZE: tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_HUGE)); break; - case FONT_SIZE_HUGER: + case HUGER_SIZE: tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_HUGER)); break; - case FONT_SIZE_INCREASE: + case INCREASE_SIZE: tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_INCREASE)); break; - case FONT_SIZE_DECREASE: + case DECREASE_SIZE: tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_DECREASE)); break; - case FONT_SIZE_INHERIT: - case FONT_SIZE_NORMAL: + case INHERIT_SIZE: + case NORMAL_SIZE: break; default: // the other tags are for internal use @@ -3328,52 +3301,52 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf, size_flag = false; } switch (curr_size) { - case FONT_SIZE_TINY: + case TINY_SIZE: tagsToOpen.push_back(html::FontTag(html::FT_SIZE_TINY)); size_flag = true; break; - case FONT_SIZE_SCRIPT: + case SCRIPT_SIZE: tagsToOpen.push_back(html::FontTag(html::FT_SIZE_SCRIPT)); size_flag = true; break; - case FONT_SIZE_FOOTNOTE: + case FOOTNOTE_SIZE: tagsToOpen.push_back(html::FontTag(html::FT_SIZE_FOOTNOTE)); size_flag = true; break; - case FONT_SIZE_SMALL: + case SMALL_SIZE: tagsToOpen.push_back(html::FontTag(html::FT_SIZE_SMALL)); size_flag = true; break; - case FONT_SIZE_LARGE: + case LARGE_SIZE: tagsToOpen.push_back(html::FontTag(html::FT_SIZE_LARGE)); size_flag = true; break; - case FONT_SIZE_LARGER: + case LARGER_SIZE: tagsToOpen.push_back(html::FontTag(html::FT_SIZE_LARGER)); size_flag = true; break; - case FONT_SIZE_LARGEST: + case LARGEST_SIZE: tagsToOpen.push_back(html::FontTag(html::FT_SIZE_LARGEST)); size_flag = true; break; - case FONT_SIZE_HUGE: + case HUGE_SIZE: tagsToOpen.push_back(html::FontTag(html::FT_SIZE_HUGE)); size_flag = true; break; - case FONT_SIZE_HUGER: + case HUGER_SIZE: tagsToOpen.push_back(html::FontTag(html::FT_SIZE_HUGER)); size_flag = true; break; - case FONT_SIZE_INCREASE: + case INCREASE_SIZE: tagsToOpen.push_back(html::FontTag(html::FT_SIZE_INCREASE)); size_flag = true; break; - case FONT_SIZE_DECREASE: + case DECREASE_SIZE: tagsToOpen.push_back(html::FontTag(html::FT_SIZE_DECREASE)); size_flag = true; break; - case FONT_SIZE_NORMAL: - case FONT_SIZE_INHERIT: + case NORMAL_SIZE: + case INHERIT_SIZE: break; default: // the other tags are for internal use @@ -3467,10 +3440,12 @@ bool Paragraph::isLineSeparator(pos_type pos) const } -bool Paragraph::isWordSeparator(pos_type pos) const +bool Paragraph::isWordSeparator(pos_type pos, bool const ignore_deleted) const { if (pos == size()) return true; + if (ignore_deleted && isDeleted(pos)) + return false; if (Inset const * inset = getInset(pos)) return !inset->isLetter(); // if we have a hard hyphen (no en- or emdash) or apostrophe @@ -3530,10 +3505,31 @@ bool Paragraph::needsCProtection(bool const fragile) const } // now check whether we have insets that need cprotection - pos_type size = d->text_.size(); - for (pos_type i = 0; i < size; ++i) - if (isInset(i) && getInset(i)->needsCProtection(maintext, fragile)) + pos_type size = pos_type(d->text_.size()); + for (pos_type i = 0; i < size; ++i) { + if (!isInset(i)) + continue; + 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()) + continue; + switch(im->cell(0)[0]->lyxCode()) { + case MATH_AMSARRAY_CODE: + case MATH_SUBSTACK_CODE: + case MATH_ENV_CODE: + case MATH_XYMATRIX_CODE: + // these need cprotection + return true; + default: + break; + } + } return false; } @@ -3642,7 +3638,7 @@ docstring Paragraph::asString(pos_type beg, pos_type end, int options, const Out os.put(c); else if (c == META_INSET && (options & AS_STR_INSETS)) { if (c == META_INSET && (options & AS_STR_PLAINTEXT)) { - LASSERT(runparams != 0, return docstring()); + LASSERT(runparams != nullptr, return docstring()); getInset(i)->plaintext(os, *runparams); } else { getInset(i)->toString(os); @@ -3764,32 +3760,43 @@ bool Paragraph::allowEmpty() const bool Paragraph::brokenBiblio() const { - // there is a problem if there is no bibitem at position 0 or - // if there is another bibitem in the paragraph. - return d->layout_->labeltype == LABEL_BIBLIO + // There is a problem if there is no bibitem at position 0 in + // paragraphs that need one, if there is another bibitem in the + // paragraph or if this paragraph is not supposed to have + // a bibitem inset at all. + return ((d->layout_->labeltype == LABEL_BIBLIO && (d->insetlist_.find(BIBITEM_CODE) != 0 - || d->insetlist_.find(BIBITEM_CODE, 1) > 0); + || d->insetlist_.find(BIBITEM_CODE, 1) > 0)) + || (d->layout_->labeltype != LABEL_BIBLIO + && d->insetlist_.find(BIBITEM_CODE) != -1)); } int Paragraph::fixBiblio(Buffer const & buffer) { - // FIXME: What about the case where paragraph is not BIBLIO - // but there is an InsetBibitem? // FIXME: when there was already an inset at 0, the return value is 1, // which does not tell whether another inset has been remove; the // cursor cannot be correctly updated. - if (d->layout_->labeltype != LABEL_BIBLIO) - return 0; - bool const track_changes = buffer.params().track_changes; int bibitem_pos = d->insetlist_.find(BIBITEM_CODE); - bool const hasbibitem0 = bibitem_pos == 0; + // The case where paragraph is not BIBLIO + if (d->layout_->labeltype != LABEL_BIBLIO) { + if (bibitem_pos == -1) + // No InsetBibitem => OK + return 0; + // There is an InsetBibitem: remove it! + d->insetlist_.release(bibitem_pos); + eraseChar(bibitem_pos, track_changes); + return (bibitem_pos == 0) ? -1 : -bibitem_pos; + } + + bool const hasbibitem0 = bibitem_pos == 0; if (hasbibitem0) { bibitem_pos = d->insetlist_.find(BIBITEM_CODE, 1); - // There was an InsetBibitem at pos 0, and no other one => OK + // There was an InsetBibitem at pos 0, + // and no other one => OK if (bibitem_pos == -1) return 0; // there is a bibitem at the 0 position, but since @@ -3804,7 +3811,7 @@ int Paragraph::fixBiblio(Buffer const & buffer) } // We need to create an inset at the beginning - Inset * inset = 0; + Inset * inset = nullptr; if (bibitem_pos > 0) { // there was one somewhere in the paragraph, let's move it inset = d->insetlist_.release(bibitem_pos); @@ -3818,6 +3825,8 @@ int Paragraph::fixBiblio(Buffer const & buffer) insertInset(0, inset, font, Change(track_changes ? Change::INSERTED : Change::UNCHANGED)); + // This is needed to get the counters right + buffer.updateBuffer(); return 1; } @@ -3876,14 +3885,14 @@ Inset * Paragraph::releaseInset(pos_type pos) Inset * Paragraph::getInset(pos_type pos) { return (pos < pos_type(d->text_.size()) && d->text_[pos] == META_INSET) - ? d->insetlist_.get(pos) : 0; + ? d->insetlist_.get(pos) : nullptr; } Inset const * Paragraph::getInset(pos_type pos) const { return (pos < pos_type(d->text_.size()) && d->text_[pos] == META_INSET) - ? d->insetlist_.get(pos) : 0; + ? d->insetlist_.get(pos) : nullptr; } @@ -4040,13 +4049,13 @@ void Paragraph::deregisterWords() void Paragraph::locateWord(pos_type & from, pos_type & to, - word_location const loc) const + word_location const loc, bool const ignore_deleted) const { switch (loc) { case WHOLE_WORD_STRICT: if (from == 0 || from == size() - || isWordSeparator(from) - || isWordSeparator(from - 1)) { + || isWordSeparator(from, ignore_deleted) + || isWordSeparator(from - 1, ignore_deleted)) { to = from; return; } @@ -4054,13 +4063,13 @@ void Paragraph::locateWord(pos_type & from, pos_type & to, case WHOLE_WORD: // If we are already at the beginning of a word, do nothing - if (!from || isWordSeparator(from - 1)) + if (!from || isWordSeparator(from - 1, ignore_deleted)) break; // fall through case PREVIOUS_WORD: // always move the cursor to the beginning of previous word - while (from && !isWordSeparator(from - 1)) + while (from && !isWordSeparator(from - 1, ignore_deleted)) --from; break; case NEXT_WORD: @@ -4071,7 +4080,7 @@ void Paragraph::locateWord(pos_type & from, pos_type & to, break; } to = from; - while (to < size() && !isWordSeparator(to)) + while (to < size() && !isWordSeparator(to, ignore_deleted)) ++to; } @@ -4150,7 +4159,7 @@ Language * Paragraph::Private::locateSpellRange( ++from; // don't check empty range if (from >= to) - return 0; + return nullptr; // get current language Language * lang = getSpellLanguage(from); pos_type last = from; @@ -4251,7 +4260,7 @@ SpellChecker::Result Paragraph::spellCheck(pos_type & from, pos_type & to, if (!d->layout_->spellcheck || !inInset().allowSpellCheck()) return result; - locateWord(from, to, WHOLE_WORD); + locateWord(from, to, WHOLE_WORD, true); if (from == to || from >= size()) return result;