X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FParagraph.cpp;h=ea2c8366a06755a8e818d9654c6d8cfa64d7d673;hb=90f7007a2e6c78ffd031e4636ff909ab1bc2ddec;hp=7a513aad64de8532564b28978a9599fae2a2cd60;hpb=2cf5de28a9ebd192da359777d9bcc1019cab4ad9;p=lyx.git diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 7a513aad64..ea2c8366a0 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -69,8 +69,10 @@ using namespace lyx::support; namespace lyx { namespace { + /// Inset identifier (above 0x10ffff, for ucs-4) char_type const META_INSET = 0x200001; + } @@ -129,12 +131,13 @@ private: class SpellCheckerState { public: - SpellCheckerState() { + SpellCheckerState() + { needs_refresh_ = true; current_change_number_ = 0; } - void setRange(FontSpan const fp, SpellChecker::Result state) + void setRange(FontSpan const & fp, SpellChecker::Result state) { Ranges result; RangesIterator et = ranges_.end(); @@ -209,20 +212,24 @@ public: return empty_; } - bool needsRefresh() const { + bool needsRefresh() const + { return needs_refresh_; } - SpellChecker::ChangeNumber currentChangeNumber() const { + SpellChecker::ChangeNumber currentChangeNumber() const + { return current_change_number_; } - void refreshRange(pos_type & first, pos_type & last) const { + void refreshRange(pos_type & first, pos_type & last) const + { first = refresh_.first; last = refresh_.last; } - void needsRefresh(pos_type pos) { + void needsRefresh(pos_type pos) + { if (needs_refresh_ && pos != -1) { if (pos < refresh_.first) refresh_.first = pos; @@ -237,13 +244,13 @@ public: needs_refresh_ = pos != -1; } - void needsCompleteRefresh(SpellChecker::ChangeNumber change_number) { + void needsCompleteRefresh(SpellChecker::ChangeNumber change_number) + { needs_refresh_ = true; refresh_.first = 0; refresh_.last = -1; current_change_number_ = change_number; } - private: typedef vector Ranges; typedef Ranges::const_iterator RangesIterator; @@ -330,6 +337,7 @@ public: /// void latexSpecialChar( otexstream & os, + BufferParams const & bparams, OutputParams const & runparams, Font const & running_font, Change const & running_change, @@ -383,9 +391,10 @@ public: Language * getSpellLanguage(pos_type const from) const; Language * locateSpellRange(pos_type & from, pos_type & to, - SkipPositions & skips) const; + SkipPositions & skips) const; - bool hasSpellerChange() const { + bool hasSpellerChange() const + { SpellChecker::ChangeNumber speller_change_number = 0; if (theSpellChecker()) speller_change_number = theSpellChecker()->changeNumber(); @@ -404,14 +413,16 @@ public: speller_state_.setRange(fp, state); } - void requestSpellCheck(pos_type pos) { + void requestSpellCheck(pos_type pos) + { if (pos == -1) speller_state_.needsCompleteRefresh(speller_state_.currentChangeNumber()); else speller_state_.needsRefresh(pos); } - void readySpellCheck() { + void readySpellCheck() + { speller_state_.needsRefresh(-1); } @@ -858,8 +869,14 @@ int Paragraph::Private::latexSurrogatePair(otexstream & os, char_type c, // FIXME: change tracking // Is this correct WRT change tracking? Encoding const & encoding = *(runparams.encoding); - docstring const latex1 = encoding.latexChar(next); - docstring const latex2 = encoding.latexChar(c); + docstring latex1 = encoding.latexChar(next).first; + if (runparams.inIPA) { + string const tipashortcut = Encodings::TIPAShortcut(next); + if (!tipashortcut.empty()) { + latex1 = from_ascii(tipashortcut); + } + } + docstring const latex2 = encoding.latexChar(c).first; if (docstring(1, next) == latex1) { // the encoding supports the combination os << latex2 << latex1; @@ -975,7 +992,7 @@ int Paragraph::Private::writeScriptChars(otexstream & os, // Stop here if there is a font attribute or encoding change. if (found && cit != end && prev_font != cit->font()) break; - docstring const latex = encoding.latexChar(next); + docstring const latex = encoding.latexChar(next).first; docstring::size_type const b1 = latex.find_first_of(from_ascii("{")); docstring::size_type const b2 = @@ -1076,6 +1093,7 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, odocstream::pos_type const len = os.os().tellp(); if (inset->forceLTR() + && !runparams.use_polyglossia && running_font.isRightToLeft() // ERT is an exception, it should be output with no // decorations at all @@ -1155,6 +1173,7 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, void Paragraph::Private::latexSpecialChar(otexstream & os, + BufferParams const & bparams, OutputParams const & runparams, Font const & running_font, Change const & running_change, @@ -1163,12 +1182,15 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, pos_type end_pos, unsigned int & column) { - char_type const c = text_[i]; + // With polyglossia, brackets and stuff need not be reversed + // in RTL scripts (see bug #8251) + char_type const c = (runparams.use_polyglossia) ? + owner_->getUChar(bparams, i) : text_[i]; if (style.pass_thru || runparams.pass_thru) { if (c != '\0') { Encoding const * const enc = runparams.encoding; - if (enc && enc->latexChar(c, true).empty()) + if (enc && !enc->encodable(c)) throw EncodingException(c); os.put(c); } @@ -1273,41 +1295,50 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, } } string script; - docstring latex = encoding.latexChar(c); + pair latex = encoding.latexChar(c); docstring nextlatex; - if (next != '\0' && next != META_INSET) - nextlatex = encoding.latexChar(next); + bool nexttipas = false; + string nexttipashortcut; + if (next != '\0' && next != META_INSET) { + nextlatex = encoding.latexChar(next).first; + if (runparams.inIPA) { + nexttipashortcut = Encodings::TIPAShortcut(next); + nexttipas = !nexttipashortcut.empty(); + } + } bool tipas = false; if (runparams.inIPA) { string const tipashortcut = Encodings::TIPAShortcut(c); if (!tipashortcut.empty()) { - latex = from_ascii(tipashortcut); + latex.first = from_ascii(tipashortcut); + latex.second = false; tipas = true; } } if (Encodings::isKnownScriptChar(c, script) - && prefixIs(latex, from_ascii("\\" + script))) - column += writeScriptChars(os, latex, + && prefixIs(latex.first, from_ascii("\\" + script))) + column += writeScriptChars(os, latex.first, running_change, encoding, i) - 1; - else if (Encodings::needsTermination(c) - && !prefixIs(nextlatex, from_ascii("\\")) - && !prefixIs(nextlatex, from_ascii("{")) - && !prefixIs(nextlatex, from_ascii("}")) - && latex.length() > 1 && latex[latex.length() - 1] != '}' - && latex[latex.length() - 1] != '-' && !tipas) { + else 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 // following characters if (next == ' ' || next == '\0') { - column += latex.length() + 1; - os << latex << "{}"; + column += latex.first.length() + 1; + os << latex.first << "{}"; } else { - column += latex.length(); - os << latex << " "; + column += latex.first.length(); + os << latex.first << " "; } } else { - column += latex.length() - 1; - os << latex; + column += latex.first.length() - 1; + os << latex.first; } break; } @@ -1343,16 +1374,19 @@ bool Paragraph::Private::latexSpecialT1(char_type const c, otexstream & os, bool Paragraph::Private::latexSpecialT3(char_type const c, otexstream & os, - pos_type /*i*/, unsigned int & /*column*/) + pos_type /*i*/, unsigned int & column) { switch (c) { case '*': case '[': case ']': - case '|': case '\"': os.put(c); return true; + case '|': + os << "\\textvertline{}"; + column += 14; + return true; default: return false; } @@ -1427,18 +1461,25 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const // we have to provide all the optional arguments here, even though // the last one is the only one we care about. // Separate handling of optional argument inset. - if (layout_->optargs != 0 || layout_->reqargs != 0) - latexArgInsets(*owner_, os, features.runparams(), - layout_->reqargs, layout_->optargs); - else - os << from_ascii(layout_->latexparam()); + if (!layout_->latexargs().empty()) { + OutputParams rp = features.runparams(); + rp.local_font = &owner_->getFirstFontSettings(bp); + latexArgInsets(*owner_, os, rp, layout_->latexargs()); + } + os << from_ascii(layout_->latexparam()); } docstring::size_type const length = ods.str().length(); // this will output "{" at the beginning, but not at the end owner_->latex(bp, f, os, features.runparams(), 0, -1, true); if (ods.str().length() > length) { - if (is_command) + if (is_command) { ods << '}'; + if (!layout_->postcommandargs().empty()) { + OutputParams rp = features.runparams(); + rp.local_font = &owner_->getFirstFontSettings(bp); + latexArgInsets(*owner_, os, rp, layout_->postcommandargs(), "post:"); + } + } string const snippet = to_utf8(ods.str()); features.addPreambleSnippet(snippet); } @@ -1446,7 +1487,7 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const if (features.runparams().flavor == OutputParams::HTML && layout_->htmltitle()) { - features.setHTMLTitle(owner_->asString(AS_STR_INSETS)); + features.setHTMLTitle(owner_->asString(AS_STR_INSETS | AS_STR_SKIPDELETE)); } // check the params. @@ -1887,16 +1928,23 @@ FontSize Paragraph::highestFontInRange char_type Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const { char_type c = d->text_[pos]; - if (!lyxrc.rtl_support) + if (!lyxrc.rtl_support || !getFontSettings(bparams, pos).isRightToLeft()) return c; + // FIXME: The arabic special casing is due to the difference of arabic + // round brackets input introduced in r18599. Check if this should be + // unified with Hebrew or at least if all bracket types should be + // handled the same (file format change in either case). + string const & lang = getFontSettings(bparams, pos).language()->lang(); + bool const arabic = lang == "arabic_arabtex" || lang == "arabic_arabi" + || lang == "farsi"; char_type uc = c; switch (c) { case '(': - uc = ')'; + uc = arabic ? c : ')'; break; case ')': - uc = '('; + uc = arabic ? c : '('; break; case '[': uc = ']'; @@ -1917,9 +1965,8 @@ char_type Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const uc = '<'; break; } - if (uc != c && getFontSettings(bparams, pos).isRightToLeft()) - return uc; - return c; + + return uc; } @@ -2129,7 +2176,7 @@ bool Paragraph::usePlainLayout() const bool Paragraph::isPassThru() const { - return inInset().getLayout().isPassThru() || d->layout_->pass_thru; + return inInset().isPassThru() || d->layout_->pass_thru; } namespace { @@ -2388,6 +2435,10 @@ void Paragraph::latex(BufferParams const & bparams, os << '{'; ++column; } + if (!style.leftdelim().empty()) { + os << style.leftdelim(); + column += style.leftdelim().size(); + } if (allowcust) column += d->startTeXParParams(bparams, os, runparams); } @@ -2418,6 +2469,11 @@ void Paragraph::latex(BufferParams const & bparams, ++column; } + if (!style.leftdelim().empty()) { + os << style.leftdelim(); + column += style.leftdelim().size(); + } + if (allowcust) column += d->startTeXParParams(bparams, os, runparams); @@ -2557,7 +2613,7 @@ void Paragraph::latex(BufferParams const & bparams, } else { if (i >= start_pos && (end_pos == -1 || i < end_pos)) { try { - d->latexSpecialChar(os, rp, running_font, runningChange, + d->latexSpecialChar(os, bparams, rp, running_font, runningChange, style, i, end_pos, column); } catch (EncodingException & e) { if (runparams.dryrun) { @@ -2608,6 +2664,11 @@ void Paragraph::latex(BufferParams const & bparams, os << "}]~"; } + if (!style.rightdelim().empty()) { + os << style.rightdelim(); + column += style.rightdelim().size(); + } + if (allowcust && d->endTeXParParams(bparams, os, runparams) && runparams.encoding != prev_encoding) { runparams.encoding = prev_encoding; @@ -2833,9 +2894,9 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf, retval += inset->xhtml(xs, np); } } else { - char_type c = d->text_[i]; + char_type c = getUChar(buf.params(), i); - if (style.pass_thru) + if (style.pass_thru || runparams.pass_thru) xs << c; else if (c == '-') { docstring str; @@ -3220,70 +3281,61 @@ char_type Paragraph::transformChar(char_type c, pos_type pos) const } -int Paragraph::checkBiblio(Buffer const & buffer) +bool Paragraph::brokenBiblio() const { - // FIXME From JS: - // This is getting more and more a mess. ...We really should clean - // up this bibitem issue for 1.6. + // 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 + && (d->insetlist_.find(BIBITEM_CODE) != 0 + || d->insetlist_.find(BIBITEM_CODE, 1) > 0); +} + + +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. - // Add bibitem insets if necessary if (d->layout_->labeltype != LABEL_BIBLIO) return 0; - bool hasbibitem = !d->insetlist_.empty() - // Insist on it being in pos 0 - && d->text_[0] == META_INSET - && d->insetlist_.begin()->inset->lyxCode() == BIBITEM_CODE; - - bool track_changes = buffer.params().trackChanges; - - docstring oldkey; - docstring oldlabel; - - // remove a bibitem in pos != 0 - // restore it later in pos 0 if necessary - // (e.g. if a user inserts contents _before_ the item) - // we're assuming there's only one of these, which there - // should be. - int erasedInsetPosition = -1; - InsetList::iterator it = d->insetlist_.begin(); - InsetList::iterator end = d->insetlist_.end(); - for (; it != end; ++it) - if (it->inset->lyxCode() == BIBITEM_CODE - && it->pos > 0) { - InsetCommand * olditem = it->inset->asInsetCommand(); - oldkey = olditem->getParam("key"); - oldlabel = olditem->getParam("label"); - erasedInsetPosition = it->pos; - eraseChar(erasedInsetPosition, track_changes); - break; - } + bool const track_changes = buffer.params().trackChanges; + int bibitem_pos = d->insetlist_.find(BIBITEM_CODE); + bool const hasbibitem0 = bibitem_pos == 0; - // There was an InsetBibitem at the beginning, and we didn't - // have to erase one. - if (hasbibitem && erasedInsetPosition < 0) + if (hasbibitem0) { + bibitem_pos = d->insetlist_.find(BIBITEM_CODE, 1); + // 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 + // there is a second one, we copy the second on the + // first. We're assuming there are at most two of + // 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); + d->insetlist_.begin()->inset = inset; + return -bibitem_pos; + } + + // We need to create an inset at the beginning + Inset * inset = 0; + if (bibitem_pos > 0) { + // there was one somewhere in the paragraph, let's move it + inset = d->insetlist_.release(bibitem_pos); + eraseChar(bibitem_pos, track_changes); + } else + // make a fresh one + inset = new InsetBibitem(const_cast(&buffer), + InsetCommandParams(BIBITEM_CODE)); - // There was an InsetBibitem at the beginning and we did have to - // erase one. So we give its properties to the beginning inset. - if (hasbibitem) { - InsetCommand * inset = d->insetlist_.begin()->inset->asInsetCommand(); - if (!oldkey.empty()) - inset->setParam("key", oldkey); - inset->setParam("label", oldlabel); - return -erasedInsetPosition; - } - - // There was no inset at the beginning, so we need to create one with - // the key and label of the one we erased. - InsetBibitem * inset = - new InsetBibitem(const_cast(&buffer), InsetCommandParams(BIBITEM_CODE)); - // restore values of previously deleted item in this par. - if (!oldkey.empty()) - inset->setParam("key", oldkey); - inset->setParam("label", oldlabel); - insertInset(0, inset, - Change(track_changes ? Change::INSERTED : Change::UNCHANGED)); + insertInset(0, inset, Change(track_changes ? Change::INSERTED + : Change::UNCHANGED)); return 1; } @@ -3712,7 +3764,7 @@ SpellChecker::Result Paragraph::spellCheck(pos_type & from, pos_type & to, wl = WordLangTuple(word, lang); - if (!word.size()) + if (word.empty()) return result; if (needsSpellCheck() || check_learned) { @@ -3809,7 +3861,7 @@ void Paragraph::Private::markMisspelledWords( void Paragraph::spellCheck() const { SpellChecker * speller = theSpellChecker(); - if (!speller || !size() ||!needsSpellCheck()) + if (!speller || empty() ||!needsSpellCheck()) return; pos_type start; pos_type endpos;