X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2FMathData.cpp;h=9bfd558fe2856d8e1475648b8c9b1963255cf25a;hb=59fa0b25928b43c8d32d19a6193dc3bd07716947;hp=7b112e9bebc34c047b144c140081be7ee5a90b82;hpb=7365a29fea7076ab9113b31b5f62bdc6791e2f2f;p=lyx.git diff --git a/src/mathed/MathData.cpp b/src/mathed/MathData.cpp index 7b112e9beb..9bfd558fe2 100644 --- a/src/mathed/MathData.cpp +++ b/src/mathed/MathData.cpp @@ -17,7 +17,7 @@ #include "InsetMathFont.h" #include "InsetMathScript.h" #include "MacroTable.h" -#include "MathMacro.h" +#include "InsetMathMacro.h" #include "MathStream.h" #include "MathSupport.h" #include "MetricsInfo.h" @@ -30,14 +30,14 @@ #include "mathed/InsetMathUnknown.h" -#include "support/debug.h" -#include "support/docstream.h" - #include "frontends/FontMetrics.h" #include "frontends/Painter.h" +#include "support/debug.h" +#include "support/docstream.h" +#include "support/gettext.h" #include "support/lassert.h" -#include +#include "support/lyxalgo.h" #include @@ -47,33 +47,43 @@ namespace lyx { MathData::MathData(Buffer * buf, const_iterator from, const_iterator to) - : base_type(from, to), buffer_(buf) + : base_type(from, to), minasc_(0), mindes_(0), slevel_(0), + sshift_(0), buffer_(buf) {} +void MathData::setBuffer(Buffer & b) +{ + buffer_ = &b; + for (MathAtom & at : *this) + at.nucleus()->setBuffer(b); +} + + MathAtom & MathData::operator[](pos_type pos) { - LASSERT(pos < size(), /**/); + LBUFERR(pos < size()); return base_type::operator[](pos); } MathAtom const & MathData::operator[](pos_type pos) const { - LASSERT(pos < size(), /**/); + LBUFERR(pos < size()); return base_type::operator[](pos); } void MathData::insert(size_type pos, MathAtom const & t) { + LBUFERR(pos <= size()); base_type::insert(begin() + pos, t); } void MathData::insert(size_type pos, MathData const & ar) { - LASSERT(pos <= size(), /**/); + LBUFERR(pos <= size()); base_type::insert(begin() + pos, ar.begin(), ar.end()); } @@ -210,11 +220,36 @@ bool MathData::contains(MathData const & ar) const } -void MathData::touch() const +bool MathData::addToMathRow(MathRow & mrow, MetricsInfo & mi) const { + bool has_contents = false; + BufferView * bv = mi.base.bv; + MathData * ar = const_cast(this); + ar->updateMacros(&bv->cursor(), mi.macrocontext, + InternalUpdate, mi.base.macro_nesting); + + + // FIXME: for completion, try to insert the relevant data in the + // mathrow (like is done for text rows). We could add a pair of + // InsetMathColor inset, but these come with extra spacing of + // their own. + DocIterator const & inlineCompletionPos = bv->inlineCompletionPos(); + bool const has_completion = inlineCompletionPos.inMathed() + && &inlineCompletionPos.cell() == this; + size_t const compl_pos = has_completion ? inlineCompletionPos.pos() : 0; + + for (size_t i = 0 ; i < size() ; ++i) { + has_contents |= (*this)[i]->addToMathRow(mrow, mi); + if (i + 1 == compl_pos) { + mrow.back().compl_text = bv->inlineCompletion(); + mrow.back().compl_unique_to = bv->inlineCompletionUniqueChars(); + } + } + return has_contents; } +#if 0 namespace { bool isInside(DocIterator const & it, MathData const & ar, @@ -229,125 +264,93 @@ bool isInside(DocIterator const & it, MathData const & ar, } } +#endif - -void MathData::metrics(MetricsInfo & mi, Dimension & dim) const +void MathData::metrics(MetricsInfo & mi, Dimension & dim, bool tight) const { frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); - dim = fm.dimension('I'); - int xascent = fm.dimension('x').ascent(); - if (xascent >= dim.asc) - xascent = (2 * dim.asc) / 3; + BufferView * bv = mi.base.bv; + int const Iascent = fm.dimension('I').ascent(); + int xascent = fm.xHeight(); + if (xascent >= Iascent) + xascent = (2 * Iascent) / 3; minasc_ = xascent; mindes_ = (3 * xascent) / 4; slevel_ = (4 * xascent) / 5; sshift_ = xascent / 4; - kerning_ = 0; - if (empty()) { - // Cache the dimension. - mi.base.bv->coordCache().arrays().add(this, dim); - return; + MathRow mrow(mi, this); + mrow.metrics(mi, dim); + + // Set a minimal ascent/descent for the cell + if (tight) + // FIXME: this is the minimal ascent seen empirically, check + // what the TeXbook says. + dim.asc = max(dim.asc, fm.xHeight()); + else { + dim.asc = max(dim.asc, fm.maxAscent()); + dim.des = max(dim.des, fm.maxDescent()); } - Cursor & cur = mi.base.bv->cursor(); - const_cast(this)->updateMacros(&cur, mi.macrocontext); + // This is one of the the few points where the drawing font is known, + // so that we can set the caret vertical dimensions. + mrow.caret_ascent = min(dim.asc, fm.maxAscent()); + mrow.caret_descent = min(dim.des, fm.maxDescent()); + /// do the same for math cells linearized in the row + MathRow caret_row = MathRow(mrow.caret_ascent, mrow.caret_descent); + for (auto const & e : mrow) + if (e.type == MathRow::BEGIN && e.ar) + bv->setMathRow(e.ar, caret_row); - DocIterator const & inlineCompletionPos = mi.base.bv->inlineCompletionPos(); - MathData const * inlineCompletionData = 0; - if (inlineCompletionPos.inMathed()) - inlineCompletionData = &inlineCompletionPos.cell(); - - dim.asc = 0; - dim.wid = 0; - Dimension d; - CoordCacheBase & coords = mi.base.bv->coordCache().insets(); - for (pos_type i = 0, n = size(); i != n; ++i) { - MathAtom const & at = operator[](i); - at->metrics(mi, d); - coords.add(at.nucleus(), d); - dim += d; - if (i == n - 1) - kerning_ = at->kerning(mi.base.bv); - - // HACK to draw completion suggestion inline - if (inlineCompletionData != this - || size_t(inlineCompletionPos.pos()) != i + 1) - continue; - - docstring const & completion = mi.base.bv->inlineCompletion(); - if (completion.length() == 0) - continue; - - dim.wid += mathed_string_width(mi.base.font, completion); - } - // Cache the dimension. - mi.base.bv->coordCache().arrays().add(this, dim); + // Cache row and dimension. + bv->setMathRow(this, mrow); + bv->coordCache().arrays().add(this, dim); } -void MathData::draw(PainterInfo & pi, int x, int y) const +void MathData::drawSelection(PainterInfo & pi, int const x, int const y) const { - //lyxerr << "MathData::draw: x: " << x << " y: " << y << endl; - BufferView & bv = *pi.base.bv; - setXY(bv, x, y); - - Dimension const & dim = bv.coordCache().getArrays().dim(this); - - if (empty()) { - pi.pain.rectangle(x, y - dim.ascent(), dim.width(), dim.height(), Color_mathline); + BufferView const * bv = pi.base.bv; + Cursor const & cur = bv->cursor(); + InsetMath const * inset = cur.inset().asInsetMath(); + if (!cur.selection() || !inset || inset->nargs() == 0) return; + + CursorSlice const s1 = cur.selBegin(); + CursorSlice const s2 = cur.selEnd(); + MathData const & c1 = inset->cell(s1.idx()); + + if (s1.idx() == s2.idx() && &c1 == this) { + // selection indide cell + Dimension const dim = bv->coordCache().getArrays().dim(&c1); + int const beg = c1.pos2x(bv, s1.pos()); + int const end = c1.pos2x(bv, s2.pos()); + pi.pain.fillRectangle(x + beg, y - dim.ascent(), + end - beg, dim.height(), Color_selection); + } else { + for (idx_type i = 0; i < inset->nargs(); ++i) { + MathData const & c = inset->cell(i); + if (&c == this && inset->idxBetween(i, s1.idx(), s2.idx())) { + // The whole cell is selected + Dimension const dim = bv->coordCache().getArrays().dim(&c); + pi.pain.fillRectangle(x, y - dim.ascent(), + dim.width(), dim.height(), + Color_selection); + } + } } +} - // don't draw outside the workarea - if (y + dim.descent() <= 0 - || y - dim.ascent() >= bv.workHeight() - || x + dim.width() <= 0 - || x >= bv. workWidth()) - return; - DocIterator const & inlineCompletionPos = bv.inlineCompletionPos(); - MathData const * inlineCompletionData = 0; - if (inlineCompletionPos.inMathed()) - inlineCompletionData = &inlineCompletionPos.cell(); +void MathData::draw(PainterInfo & pi, int const x, int const y) const +{ + //lyxerr << "MathData::draw: x: " << x << " y: " << y << endl; + setXY(*pi.base.bv, x, y); - CoordCacheBase & coords = pi.base.bv->coordCache().insets(); - for (size_t i = 0, n = size(); i != n; ++i) { - MathAtom const & at = operator[](i); - coords.add(at.nucleus(), x, y); - at->drawSelection(pi, x, y); - at->draw(pi, x, y); - x += coords.dim(at.nucleus()).wid; - - // Is the inline completion here? - if (inlineCompletionData != this - || size_t(inlineCompletionPos.pos()) != i + 1) - continue; - docstring const & completion = bv.inlineCompletion(); - if (completion.length() == 0) - continue; - FontInfo f = pi.base.font; - - // draw the unique and the non-unique completion part - // Note: this is not time-critical as it is - // only done once per screen. - size_t uniqueTo = bv.inlineCompletionUniqueChars(); - docstring s1 = completion.substr(0, uniqueTo); - docstring s2 = completion.substr(uniqueTo); - - if (s1.size() > 0) { - f.setColor(Color_inlinecompletion); - pi.pain.text(x, y, s1, f); - x += mathed_string_width(f, s1); - } - - if (s2.size() > 0) { - f.setColor(Color_nonunique_inlinecompletion); - pi.pain.text(x, y, s2, f); - x += mathed_string_width(f, s2); - } - } + drawSelection(pi, x, y); + MathRow const & mrow = pi.base.bv->mathRow(this); + mrow.draw(pi, x, y); } @@ -377,20 +380,40 @@ void MathData::drawT(TextPainter & pain, int x, int y) const } -void MathData::updateMacros(Cursor * cur, MacroContext const & mc) +int MathData::kerning(BufferView const * bv) const +{ + return bv->mathRow(this).kerning(bv); +} + + +void MathData::updateBuffer(ParIterator const & it, UpdateType utype) +{ + // pass down + for (size_t i = 0, n = size(); i != n; ++i) { + MathAtom & at = operator[](i); + at.nucleus()->updateBuffer(it, utype); + } +} + + +void MathData::updateMacros(Cursor * cur, MacroContext const & mc, + UpdateType utype, int nesting) { // If we are editing a macro, we cannot update it immediately, - // as no undo steps will be recorded (bug 6208). + // otherwise wrong undo steps will be recorded (bug 6208). InsetMath const * inmath = cur ? cur->inset().asInsetMath() : 0; - MathMacro const * inmacro = inmath ? inmath->asMacro() : 0; + InsetMathMacro const * inmacro = inmath ? inmath->asMacro() : 0; docstring const edited_name = inmacro ? inmacro->name() : docstring(); // go over the array and look for macros for (size_t i = 0; i < size(); ++i) { - MathMacro * macroInset = operator[](i).nucleus()->asMacro(); - if (!macroInset || macroInset->name_[0] == '^' - || macroInset->name_[0] == '_' - || macroInset->name() == edited_name) + InsetMathMacro * macroInset = operator[](i).nucleus()->asMacro(); + if (!macroInset || macroInset->macroName().empty() + || macroInset->macroName()[0] == '^' + || macroInset->macroName()[0] == '_' + || (macroInset->name() == edited_name + && macroInset->displayMode() == + InsetMathMacro::DISPLAY_UNFOLDED)) continue; // get macro @@ -404,25 +427,23 @@ void MathData::updateMacros(Cursor * cur, MacroContext const & mc) } // store old and compute new display mode - MathMacro::DisplayMode newDisplayMode; - MathMacro::DisplayMode oldDisplayMode = macroInset->displayMode(); + InsetMathMacro::DisplayMode newDisplayMode; + InsetMathMacro::DisplayMode oldDisplayMode = macroInset->displayMode(); newDisplayMode = macroInset->computeDisplayMode(); // arity changed or other reason to detach? - if (oldDisplayMode == MathMacro::DISPLAY_NORMAL + if (oldDisplayMode == InsetMathMacro::DISPLAY_NORMAL && (macroInset->arity() != macroNumArgs || macroInset->optionals() != macroOptionals - || newDisplayMode == MathMacro::DISPLAY_UNFOLDED)) { - + || newDisplayMode == InsetMathMacro::DISPLAY_UNFOLDED)) detachMacroParameters(cur, i); - } // the macro could have been copied while resizing this macroInset = operator[](i).nucleus()->asMacro(); // Cursor in \label? - if (newDisplayMode != MathMacro::DISPLAY_UNFOLDED - && oldDisplayMode == MathMacro::DISPLAY_UNFOLDED) { + if (newDisplayMode != InsetMathMacro::DISPLAY_UNFOLDED + && oldDisplayMode == InsetMathMacro::DISPLAY_UNFOLDED) { // put cursor in front of macro if (cur) { int macroSlice = cur->find(macroInset); @@ -436,48 +457,46 @@ void MathData::updateMacros(Cursor * cur, MacroContext const & mc) macroInset->setDisplayMode(newDisplayMode); // arity changed? - if (newDisplayMode == MathMacro::DISPLAY_NORMAL + if (newDisplayMode == InsetMathMacro::DISPLAY_NORMAL && (macroInset->arity() != macroNumArgs || macroInset->optionals() != macroOptionals)) { // is it a virgin macro which was never attached to parameters? bool fromInitToNormalMode - = (oldDisplayMode == MathMacro::DISPLAY_INIT - || oldDisplayMode == MathMacro::DISPLAY_INTERACTIVE_INIT) - && newDisplayMode == MathMacro::DISPLAY_NORMAL; - + = (oldDisplayMode == InsetMathMacro::DISPLAY_INIT + || oldDisplayMode == InsetMathMacro::DISPLAY_INTERACTIVE_INIT) + && newDisplayMode == InsetMathMacro::DISPLAY_NORMAL; + // if the macro was entered interactively (i.e. not by paste or during // loading), it should not be greedy, but the cursor should // automatically jump into the macro when behind - bool interactive = (oldDisplayMode == MathMacro::DISPLAY_INTERACTIVE_INIT); - + bool interactive = (oldDisplayMode == InsetMathMacro::DISPLAY_INTERACTIVE_INIT); + // attach parameters attachMacroParameters(cur, i, macroNumArgs, macroOptionals, fromInitToNormalMode, interactive, appetite); - - if (cur) { - // FIXME: proper anchor handling, this removes the selection + + if (cur) cur->updateInsets(&cur->bottom().inset()); - cur->clearSelection(); - } } // Give macro the chance to adapt to new situation. - // The macroInset could be invalid now because it was put into a script + // The macroInset could be invalid now because it was put into a script // inset and therefore "deep" copied. So get it again from the MathData. InsetMath * inset = operator[](i).nucleus(); if (inset->asScriptInset()) inset = inset->asScriptInset()->nuc()[0].nucleus(); - LASSERT(inset->asMacro(), /**/); - inset->asMacro()->updateRepresentation(); + LASSERT(inset->asMacro(), continue); + inset->asMacro()->updateRepresentation(cur, mc, utype, nesting + 1); } } -void MathData::detachMacroParameters(Cursor * cur, const size_type macroPos) +void MathData::detachMacroParameters(DocIterator * cur, const size_type macroPos) { - MathMacro * macroInset = operator[](macroPos).nucleus()->asMacro(); - Buffer * buf = cur->buffer(); - + InsetMathMacro * macroInset = operator[](macroPos).nucleus()->asMacro(); + // We store this now, because the inset pointer will be invalidated in the scond loop below + size_t const optionals = macroInset->optionals(); + // detach all arguments vector detachedArgs; if (macroPos + 1 == size()) @@ -485,7 +504,7 @@ void MathData::detachMacroParameters(Cursor * cur, const size_type macroPos) macroInset->detachArguments(detachedArgs, true); else macroInset->detachArguments(detachedArgs, false); - + // find cursor slice int curMacroSlice = -1; if (cur) @@ -499,58 +518,61 @@ void MathData::detachMacroParameters(Cursor * cur, const size_type macroPos) cur->cutOff(curMacroSlice, argSlices); cur->pop_back(); } - - // only [] after the last non-empty argument can be dropped later + + // only [] after the last non-empty argument can be dropped later size_t lastNonEmptyOptional = 0; - for (size_t l = 0; l < detachedArgs.size() && l < macroInset->optionals(); ++l) { + for (size_t l = 0; l < detachedArgs.size() && l < optionals; ++l) { if (!detachedArgs[l].empty()) lastNonEmptyOptional = l; } - + // optional arguments to be put back? pos_type p = macroPos + 1; size_t j = 0; - for (; j < detachedArgs.size() && j < macroInset->optionals(); ++j) { + // We do not want to use macroInset below, the insert() call in + // the loop will invalidate it. + macroInset = 0; + for (; j < detachedArgs.size() && j < optionals; ++j) { // another non-empty parameter follows? bool canDropEmptyOptional = j >= lastNonEmptyOptional; - + // then we can drop empty optional parameters if (detachedArgs[j].empty() && canDropEmptyOptional) { if (curMacroIdx == j) (*cur)[curMacroSlice - 1].pos() = macroPos + 1; continue; } - + // Otherwise we don't drop an empty optional, put it back normally MathData optarg; asArray(from_ascii("[]"), optarg); MathData & arg = detachedArgs[j]; - + // look for "]", i.e. put a brace around? InsetMathBrace * brace = 0; for (size_t q = 0; q < arg.size(); ++q) { if (arg[q]->getChar() == ']') { // put brace - brace = new InsetMathBrace(buf); + brace = new InsetMathBrace(buffer_); break; } } - + // put arg between [] if (brace) { brace->cell(0) = arg; optarg.insert(1, MathAtom(brace)); } else optarg.insert(1, arg); - + // insert it into the array insert(p, optarg); p += optarg.size(); - + // cursor in macro? if (curMacroSlice == -1) continue; - + // cursor in optional argument of macro? if (curMacroIdx == j) { if (brace) { @@ -563,21 +585,21 @@ void MathData::detachMacroParameters(Cursor * cur, const size_type macroPos) // cursor right of macro (*cur)[curMacroSlice - 1].pos() += optarg.size(); } - + // put them back into the MathData for (; j < detachedArgs.size(); ++j, ++p) { MathData const & arg = detachedArgs[j]; - if (arg.size() == 1 + if (arg.size() == 1 && !arg[0]->asScriptInset() && !(arg[0]->asMacro() && arg[0]->asMacro()->arity() > 0)) insert(p, arg[0]); else insert(p, MathAtom(new InsetMathBrace(arg))); - + // cursor in macro? if (curMacroSlice == -1) continue; - + // cursor in j-th argument of macro? if (curMacroIdx == j) { if (operator[](p).nucleus()->asBraceInset()) { @@ -591,28 +613,25 @@ void MathData::detachMacroParameters(Cursor * cur, const size_type macroPos) } else if ((*cur)[curMacroSlice - 1].pos() >= int(p)) ++(*cur)[curMacroSlice - 1].pos(); } - - if (cur) { - // FIXME: proper anchor handling, this removes the selection - cur->clearSelection(); + + if (cur) cur->updateInsets(&cur->bottom().inset()); - } } -void MathData::attachMacroParameters(Cursor * cur, +void MathData::attachMacroParameters(Cursor * cur, const size_type macroPos, const size_type macroNumArgs, const int macroOptionals, const bool fromInitToNormalMode, const bool interactiveInit, const size_t appetite) { - MathMacro * macroInset = operator[](macroPos).nucleus()->asMacro(); + InsetMathMacro * macroInset = operator[](macroPos).nucleus()->asMacro(); - // start at atom behind the macro again, maybe with some new arguments + // start at atom behind the macro again, maybe with some new arguments // from the detach phase above, to add them back into the macro inset size_t p = macroPos + 1; vector detachedArgs; MathAtom scriptToPutAround; - + // find cursor slice again of this MathData int thisSlice = -1; if (cur) @@ -620,7 +639,7 @@ void MathData::attachMacroParameters(Cursor * cur, int thisPos = -1; if (thisSlice != -1) thisPos = (*cur)[thisSlice].pos(); - + // find arguments behind the macro if (!interactiveInit) { collectOptionalParameters(cur, macroOptionals, detachedArgs, p, @@ -628,29 +647,36 @@ void MathData::attachMacroParameters(Cursor * cur, } collectParameters(cur, macroNumArgs, detachedArgs, p, scriptToPutAround, macroPos, thisPos, thisSlice, appetite); - + // attach arguments back to macro inset macroInset->attachArguments(detachedArgs, macroNumArgs, macroOptionals); - + // found tail script? E.g. \foo{a}b^x if (scriptToPutAround.nucleus()) { + InsetMathScript * scriptInset = + scriptToPutAround.nucleus()->asScriptInset(); + // In the math parser we remove empty braces in the base + // of a script inset, but we have to restore them here. + if (scriptInset->nuc().empty()) { + MathData ar; + scriptInset->nuc().push_back( + MathAtom(new InsetMathBrace(ar))); + } // put macro into a script inset - scriptToPutAround.nucleus()->asScriptInset()->nuc()[0] - = operator[](macroPos); + scriptInset->nuc()[0] = operator[](macroPos); operator[](macroPos) = scriptToPutAround; // go into the script inset nucleus if (cur && thisPos == int(macroPos)) cur->append(0, 0); - + // get pointer to "deep" copied macro inset - InsetMathScript * scriptInset - = operator[](macroPos).nucleus()->asScriptInset(); - macroInset = scriptInset->nuc()[0].nucleus()->asMacro(); + scriptInset = operator[](macroPos).nucleus()->asScriptInset(); + macroInset = scriptInset->nuc()[0].nucleus()->asMacro(); } - + // remove them from the MathData - erase(begin() + macroPos + 1, begin() + p); + erase(macroPos + 1, p); // cursor outside this MathData? if (thisSlice == -1) @@ -659,7 +685,7 @@ void MathData::attachMacroParameters(Cursor * cur, // fix cursor if right of p if (thisPos >= int(p)) (*cur)[thisSlice].pos() -= p - (macroPos + 1); - + // was the macro inset just inserted interactively and was now folded // and the cursor is just behind? if ((*cur)[thisSlice].pos() == int(macroPos + 1) @@ -675,29 +701,32 @@ void MathData::attachMacroParameters(Cursor * cur, } -void MathData::collectOptionalParameters(Cursor * cur, - const size_type numOptionalParams, vector & params, +void MathData::collectOptionalParameters(Cursor * cur, + const size_type numOptionalParams, vector & params, size_t & pos, MathAtom & scriptToPutAround, const pos_type macroPos, const int thisPos, const int thisSlice) { Buffer * buf = cur ? cur->buffer() : 0; // insert optional arguments? - while (params.size() < numOptionalParams + while (params.size() < numOptionalParams && pos < size() && !scriptToPutAround.nucleus()) { // is a [] block following which could be an optional parameter? if (operator[](pos)->getChar() != '[') break; - - // found possible optional argument, look for "]" + + // found possible optional argument, look for pairing "]" + int count = 1; size_t right = pos + 1; for (; right < size(); ++right) { MathAtom & cell = operator[](right); - if (cell->getChar() == ']') + if (cell->getChar() == '[') + ++count; + else if (cell->getChar() == ']' && --count == 0) // found right end break; - + // maybe "]" with a script around? InsetMathScript * script = cell.nucleus()->asScriptInset(); if (!script) @@ -710,16 +739,16 @@ void MathData::collectOptionalParameters(Cursor * cur, break; } } - + // found? if (right >= size()) { // no ] found, so it's not an optional argument break; } - + // add everything between [ and ] as optional argument MathData optarg(buf, begin() + pos + 1, begin() + right); - + // a brace? bool brace = false; if (optarg.size() == 1 && optarg[0]->asBraceInset()) { @@ -727,9 +756,11 @@ void MathData::collectOptionalParameters(Cursor * cur, params.push_back(optarg[0]->asBraceInset()->cell(0)); } else params.push_back(optarg); - + // place cursor in optional argument of macro - if (thisSlice != -1 + // Note: The two expressions on the first line are equivalent + // (see caller), but making this explicit pleases coverity. + if (cur && thisSlice != -1 && thisPos >= int(pos) && thisPos <= int(right)) { int paramPos = max(0, thisPos - int(pos) - 1); vector x; @@ -747,37 +778,40 @@ void MathData::collectOptionalParameters(Cursor * cur, // fill up empty optional parameters while (params.size() < numOptionalParams) - params.push_back(MathData()); + params.push_back(MathData()); } -void MathData::collectParameters(Cursor * cur, - const size_type numParams, vector & params, +void MathData::collectParameters(Cursor * cur, + const size_type numParams, vector & params, size_t & pos, MathAtom & scriptToPutAround, const pos_type macroPos, const int thisPos, const int thisSlice, - const size_t appetite) + const size_t appetite) { size_t startSize = params.size(); - + // insert normal arguments while (params.size() < numParams && params.size() - startSize < appetite && pos < size() && !scriptToPutAround.nucleus()) { MathAtom & cell = operator[](pos); - + // fix cursor vector argSlices; int argPos = 0; - if (thisSlice != -1 && thisPos == int(pos)) - cur->cutOff(thisSlice, argSlices); - + // Note: The two expressions on the first line are equivalent + // (see caller), but making this explicit pleases coverity. + if (cur && thisSlice != -1 + && thisPos == int(pos)) + cur->cutOff(thisSlice, argSlices); + // which kind of parameter is it? In {}? With index x^n? InsetMathBrace const * brace = cell->asBraceInset(); if (brace) { // found brace, convert into argument params.push_back(brace->cell(0)); - + // cursor inside of the brace or just in front of? if (thisPos == int(pos) && !argSlices.empty()) { argPos = argSlices[0].pos(); @@ -792,10 +826,10 @@ void MathData::collectParameters(Cursor * cur, params.push_back(script->nuc()[0]->asBraceInset()->cell(0)); else params.push_back(script->nuc()); - + // script will be put around below scriptToPutAround = cell; - + // this should only happen after loading, so make cursor handling simple if (thisPos >= int(macroPos) && thisPos <= int(macroPos + numParams)) { argSlices.clear(); @@ -808,34 +842,29 @@ void MathData::collectParameters(Cursor * cur, array.insert(0, cell); params.push_back(array); } - + // put cursor in argument again - if (thisSlice != - 1 && thisPos == int(pos)) { + // Note: The first two expressions on the first line are + // equivalent (see caller), but making this explicit pleases + // coverity. + if (cur && thisSlice != -1 && thisPos == int(pos)) { cur->append(params.size() - 1, argPos); cur->append(argSlices); (*cur)[thisSlice].pos() = macroPos; } - + ++pos; - } + } } int MathData::pos2x(BufferView const * bv, size_type pos) const -{ - return pos2x(bv, pos, 0); -} - - -int MathData::pos2x(BufferView const * bv, size_type pos, int glue) const { int x = 0; size_type target = min(pos, size()); - CoordCacheBase const & coords = bv->coordCache().getInsets(); + CoordCache::Insets const & coords = bv->coordCache().getInsets(); for (size_type i = 0; i < target; ++i) { const_iterator it = begin() + i; - if ((*it)->getChar() == ' ') - x += glue; //lyxerr << "char: " << (*it)->getChar() // << "width: " << (*it)->width() << endl; x += coords.dim((*it).nucleus()).wid; @@ -845,22 +874,14 @@ int MathData::pos2x(BufferView const * bv, size_type pos, int glue) const MathData::size_type MathData::x2pos(BufferView const * bv, int targetx) const -{ - return x2pos(bv, targetx, 0); -} - - -MathData::size_type MathData::x2pos(BufferView const * bv, int targetx, int glue) const { const_iterator it = begin(); int lastx = 0; int currx = 0; - CoordCacheBase const & coords = bv->coordCache().getInsets(); + CoordCache::Insets const & coords = bv->coordCache().getInsets(); // find first position after targetx - for (; currx < targetx && it < end(); ++it) { + for (; currx < targetx && it != end(); ++it) { lastx = currx; - if ((*it)->getChar() == ' ') - currx += glue; currx += coords.dim((*it).nucleus()).wid; } @@ -875,7 +896,7 @@ MathData::size_type MathData::x2pos(BufferView const * bv, int targetx, int glue * See bug 1918 for details. **/ if (it != begin() && currx >= targetx - && ((*boost::prior(it))->asNestInset() + && ((*prev(it, 1))->asNestInset() || abs(lastx - targetx) < abs(currx - targetx))) { --it; } @@ -931,6 +952,20 @@ int MathData::yo(BufferView const & bv) const } +MathClass MathData::mathClass() const +{ + MathClass res = MC_UNKNOWN; + for (MathAtom const & at : *this) { + MathClass mc = at->mathClass(); + if (res == MC_UNKNOWN) + res = mc; + else if (mc != MC_UNKNOWN && res != mc) + return MC_ORD; + } + return res == MC_UNKNOWN ? MC_ORD : res; +} + + ostream & operator<<(ostream & os, MathData const & ar) { odocstringstream oss;