From 71e8668375ae367b07dfe1000e7f0410ef1013db Mon Sep 17 00:00:00 2001 From: Abdelrazak Younes Date: Tue, 17 Apr 2007 13:15:00 +0000 Subject: [PATCH] Fix bug 1395 by Stefan Schimanski: Locking counter added to MacroData: it is increased before drawing/ metric calculations and decreased afterwards in InsetMathMacro. If a macro is already locked at that point, "Self reference: \foo" is drawn instead of the macro definition to avoid endless loops. Moreover inside of the arguments of the macro the counter is temporarily decreased as those cases do not cause loops. (fixes bug #1395) git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@17836 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/mathed/InsetMath.h | 1 + src/mathed/InsetMathBrace.h | 7 +- src/mathed/InsetMathMacro.C | 89 ++++++++++++++++++------- src/mathed/InsetMathMacro.h | 22 +++--- src/mathed/MathData.C | 118 +++++++++++++++++++++------------ src/mathed/MathData.h | 5 +- src/mathed/MathFactory.C | 10 +-- src/mathed/MathMacroTable.C | 2 +- src/mathed/MathMacroTable.h | 13 +++- src/mathed/MathMacroTemplate.C | 2 +- 10 files changed, 176 insertions(+), 93 deletions(-) diff --git a/src/mathed/InsetMath.h b/src/mathed/InsetMath.h index 6602d98b9c..508f9af95d 100644 --- a/src/mathed/InsetMath.h +++ b/src/mathed/InsetMath.h @@ -113,6 +113,7 @@ public: virtual InsetMathAMSArray const * asAMSArrayInset() const { return 0; } virtual InsetMathArray * asArrayInset() { return 0; } virtual InsetMathArray const * asArrayInset() const { return 0; } + virtual InsetMathBrace * asBraceInset() { return 0; } virtual InsetMathBrace const * asBraceInset() const { return 0; } virtual InsetMathChar const * asCharInset() const { return 0; } virtual InsetMathDelim * asDelimInset() { return 0; } diff --git a/src/mathed/InsetMathBrace.h b/src/mathed/InsetMathBrace.h index 3d581dc023..f7c399a9c7 100644 --- a/src/mathed/InsetMathBrace.h +++ b/src/mathed/InsetMathBrace.h @@ -25,8 +25,6 @@ public: InsetMathBrace(); /// InsetMathBrace(MathArray const & ar); - /// - InsetMathBrace const * asBraceInset() const { return this; } /// we write extra braces in any case... bool extraBraces() const { return true; } /// @@ -47,6 +45,11 @@ public: void mathmlize(MathStream &) const; /// void infoize(odocstream & os) const; + + /// identifies brace insets + InsetMathBrace * asBraceInset() { return this; } + /// identifies brace insets + InsetMathBrace const * asBraceInset() const { return this; } private: virtual std::auto_ptr doClone() const; }; diff --git a/src/mathed/InsetMathMacro.C b/src/mathed/InsetMathMacro.C index 43cbed7c31..6db0b05e45 100644 --- a/src/mathed/InsetMathMacro.C +++ b/src/mathed/InsetMathMacro.C @@ -33,8 +33,49 @@ using std::endl; using std::vector; -MathMacro::MathMacro(docstring const & name, int numargs) - : InsetMathNest(numargs), name_(name) +/// This class is the value of a macro argument, technically +/// a wrapper of the cells of MathMacro. +class MathMacroArgumentValue : public InsetMathDim { +public: + /// + MathMacroArgumentValue(MathArray const * value) : value_(value) {} + /// + bool metrics(MetricsInfo & mi, Dimension & dim) const; + /// + void draw(PainterInfo &, int x, int y) const; + +private: + std::auto_ptr doClone() const; + MathArray const * value_; +}; + + +auto_ptr MathMacroArgumentValue::doClone() const +{ + return auto_ptr(new MathMacroArgumentValue(*this)); +} + + +bool MathMacroArgumentValue::metrics(MetricsInfo & mi, Dimension & dim) const +{ + value_->metrics(mi, dim); + metricsMarkers2(dim); + if (dim_ == dim) + return false; + dim_ = dim; + return true; +} + + +void MathMacroArgumentValue::draw(PainterInfo & pi, int x, int y) const +{ + value_->draw(pi, x, y); +} + + + +MathMacro::MathMacro(docstring const & name) + : InsetMathNest(0), name_(name) {} @@ -80,7 +121,12 @@ bool MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const dim.des += c.height() + 10; } } else { - MacroTable::globalMacros().get(name()).expand(cells_, expanded_); + // create MathMacroArgumentValue object pointing to the cells of the macro + MacroData const & macro = MacroTable::globalMacros().get(name()); + vector values(nargs()); + for (size_t i = 0; i != nargs(); ++i) + values[i].insert(0, MathAtom(new MathMacroArgumentValue(&cells_[i]))); + macro.expand(values, expanded_); expanded_.metrics(mi, dim); } metricsMarkers2(dim); @@ -141,18 +187,23 @@ void MathMacro::validate(LaTeXFeatures & features) const InsetBase * MathMacro::editXY(LCursor & cur, int x, int y) { // We may have 0 arguments, but InsetMathNest requires at least one. - if (nargs() > 0) { - // Prevent crash due to cold coordcache - // FIXME: This is only a workaround, the call of - // InsetMathNest::editXY is correct. The correct fix would - // ensure that the coordcache of the arguments is valid. - if (!editing(&cur.bv())) { - edit(cur, true); - return this; - } + if (nargs() > 0) return InsetMathNest::editXY(cur, x, y); - } - return this; + else + return this; +} + + +void MathMacro::detachArguments(std::vector &args) +{ + args = cells_; + cells_ = std::vector(); +} + + +void MathMacro::attachArguments(std::vector const &args) +{ + cells_ = args; } @@ -179,31 +230,22 @@ bool MathMacro::notifyCursorLeaves(LCursor & cur) void MathMacro::maple(MapleStream & os) const { - updateExpansion(); lyx::maple(expanded_, os); } void MathMacro::mathmlize(MathStream & os) const { - updateExpansion(); lyx::mathmlize(expanded_, os); } void MathMacro::octave(OctaveStream & os) const { - updateExpansion(); lyx::octave(expanded_, os); } -void MathMacro::updateExpansion() const -{ - //expanded_.substitute(*this); -} - - void MathMacro::infoize(odocstream & os) const { os << "Macro: " << name(); @@ -213,7 +255,6 @@ void MathMacro::infoize(odocstream & os) const void MathMacro::infoize2(odocstream & os) const { os << "Macro: " << name(); - } diff --git a/src/mathed/InsetMathMacro.h b/src/mathed/InsetMathMacro.h index cc2be0a014..a1d1144922 100644 --- a/src/mathed/InsetMathMacro.h +++ b/src/mathed/InsetMathMacro.h @@ -26,7 +26,11 @@ namespace lyx { class MathMacro : public InsetMathNest { public: /// A macro can be built from an existing template - MathMacro(docstring const & name, int numargs); + MathMacro(docstring const & name); + /// + virtual MathMacro * asMacro() { return this; } + /// + virtual MathMacro const * asMacro() const { return this; } /// void draw(PainterInfo & pi, int x, int y) const; /// @@ -38,6 +42,8 @@ public: { drawMarkers2(pi, x, y); } /// bool metrics(MetricsInfo & mi, Dimension & dim) const; + /// + bool metricsExpanded(MetricsInfo & mi, Dimension & dim) const; /// get cursor position void cursorPos(BufferView const & bv, CursorSlice const & sl, bool boundary, int & x, int & y) const; @@ -52,8 +58,10 @@ public: /// docstring name() const; /// - void setExpansion(MathArray const & exp, MathArray const & args) const; - + void detachArguments(std::vector &args); + /// + void attachArguments(std::vector const &args); + /// void validate(LaTeXFeatures &) const; @@ -70,14 +78,10 @@ public: private: virtual std::auto_ptr doClone() const; - /// - void updateExpansion() const; - /// - void expand() const; - + /// name of macro docstring name_; - /// the unexpanded macro defintition + /// the macro template mutable MathArray tmpl_; /// the macro substituted with our args mutable MathArray expanded_; diff --git a/src/mathed/MathData.C b/src/mathed/MathData.C index b2ef50fb97..70a256c708 100644 --- a/src/mathed/MathData.C +++ b/src/mathed/MathData.C @@ -14,6 +14,7 @@ #include "InsetMathFont.h" #include "InsetMathScript.h" #include "InsetMathMacro.h" +#include "InsetMathBrace.h" #include "MathMacroTable.h" #include "MathStream.h" #include "MathSupport.h" @@ -239,7 +240,6 @@ bool isInside(DocIterator const & it, MathArray const & ar, } - void MathArray::metrics(MetricsInfo & mi) const { frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); @@ -256,37 +256,16 @@ void MathArray::metrics(MetricsInfo & mi) const if (empty()) return; + const_cast(this)->updateMacros( mi ); + dim_.asc = 0; dim_.wid = 0; - Dimension d; - //BufferView & bv = *mi.base.bv; - //Buffer const & buf = *bv.buffer(); - for (size_t i = 0, n = size(); i != n; ++i) { + Dimension d; + for (size_t i = 0; i != size(); ++i) { MathAtom const & at = operator[](i); -#if 0 - MathMacro const * mac = at->asMacro(); - if (mac && buf.hasMacro(mac->name())) { - MacroData const & tmpl = buf.getMacro(mac->name()); - int numargs = tmpl.numargs(); - if (i + numargs > n) - numargs = n - i - 1; - lyxerr << "metrics:found macro: " << mac->name() - << " numargs: " << numargs << endl; - if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) { - MathArray args(begin() + i + 1, begin() + i + numargs + 1); - MathArray exp; - tmpl.expand(args, exp); - mac->setExpansion(exp, args); - mac->metricsExpanded(mi, d); - dim_.wid += mac->widthExpanded(); - i += numargs; - continue; - } - } -#endif at->metrics(mi, d); dim_ += d; - if (i == n - 1) + if (i == size() - 1) kerning_ = at->kerning(); } } @@ -312,23 +291,6 @@ void MathArray::draw(PainterInfo & pi, int x, int y) const for (size_t i = 0, n = size(); i != n; ++i) { MathAtom const & at = operator[](i); -#if 0 - Buffer const & buf = bv.buffer(); - // special macro handling - MathMacro const * mac = at->asMacro(); - if (mac && buf.hasMacro(mac->name())) { - MacroData const & tmpl = buf.getMacro(mac->name()); - int numargs = tmpl.numargs(); - if (i + numargs > n) - numargs = n - i - 1; - if (!isInside(bv.cursor(), *this, i + 1, i + numargs + 1)) { - mac->drawExpanded(pi, x, y); - x += mac->widthExpanded(); - i += numargs; - continue; - } - } -#endif bv.coordCache().insets().add(at.nucleus(), x, y); at->drawSelection(pi, x, y); at->draw(pi, x, y); @@ -363,6 +325,74 @@ void MathArray::drawT(TextPainter & pain, int x, int y) const } +void MathArray::updateMacros(MetricsInfo & mi) { + Buffer *buf = mi.base.bv->buffer(); + + // go over the array and look for macros + for (size_t i = 0; i != size(); ++i) { + InsetMath * at = operator[](i).nucleus(); + MathMacro * macroInset = at->asMacro(); + if (macroInset) { + // get arity of macro or 0 if unknown + size_t numargs = 0; + if (buf->hasMacro(macroInset->name())) { + MacroData const & macro = buf->getMacro(macroInset->name()); + numargs = macro.numargs(); + } + + // arity of macro changed? + if (macroInset->nargs() != numargs) { + // detach all arguments + std::vector detachedArgs; + macroInset->detachArguments( detachedArgs ); + + // too many arguments in the macro inset? + if (detachedArgs.size() > numargs) { + // insert overlap back as braces + std::vector overlap(detachedArgs.begin()+numargs, detachedArgs.end()); + detachedArgs.erase(detachedArgs.begin()+numargs, detachedArgs.end()); + for (size_t j = 0; j < overlap.size(); ++j) { + MathArray const & arg = overlap[j]; + if (arg.size() == 1) + insert(i+j+1, MathAtom(new InsetMathBrace(arg))); + else + insert(i+j+1, arg[0]); + } + i += overlap.size(); + } else { + // insert some cells from the array into the macro inset + size_t missingArgs = numargs-detachedArgs.size(); + size_t j; + for (j = 0; j < missingArgs && i+1+j < size(); ++j) { + MathAtom & cell = operator[](i+1+j); + InsetMathBrace const * brace = cell->asBraceInset(); + if (brace) { + // found brace, convert into argument + detachedArgs.push_back(brace->cell(0)); + } else { + MathArray array; + array.insert(0, cell); + detachedArgs.push_back(array); + } + } + + // remove them from the array + erase(begin()+i+1, begin()+i+1+j); + + // enough for the macro inset now? + // Add some empty ones of necessary + for (; j < missingArgs; ++j) + detachedArgs.insert(detachedArgs.end(), MathArray()); + } + + // attach arguments back to macro inset + macroInset->attachArguments(detachedArgs); + } + } + } +} + + int MathArray::pos2x(size_type pos) const { return pos2x(pos, 0); diff --git a/src/mathed/MathData.h b/src/mathed/MathData.h index d3c916c28e..a2ea8c837e 100644 --- a/src/mathed/MathData.h +++ b/src/mathed/MathData.h @@ -161,7 +161,7 @@ public: int kerning() const { return kerning_; } /// void swap(MathArray & ar) { base_type::swap(ar); } - + protected: /// cached dimensions of cell mutable Dimension dim_; @@ -172,6 +172,9 @@ protected: mutable int sshift_; mutable int kerning_; + /// attach/detach brace inset to macros + void updateMacros(MetricsInfo & mi); + private: /// is this an exact match at this position? bool find1(MathArray const & ar, size_type pos) const; diff --git a/src/mathed/MathFactory.C b/src/mathed/MathFactory.C index 62bcef30db..2be23f6915 100644 --- a/src/mathed/MathFactory.C +++ b/src/mathed/MathFactory.C @@ -392,15 +392,7 @@ MathAtom createInsetMath(docstring const & s) if (s == "vphantom") return MathAtom(new InsetMathPhantom(InsetMathPhantom::vphantom)); - if (MacroTable::globalMacros().has(s)) - return MathAtom(new MathMacro(s, - MacroTable::globalMacros().get(s).numargs())); - //if (MacroTable::localMacros().has(s)) - // return MathAtom(new MathMacro(s, - // MacroTable::localMacros().get(s).numargs())); - - //lyxerr << "creating unknown inset '" << s << "'" << endl; - return MathAtom(new InsetMathUnknown(s)); + return MathAtom(new MathMacro(s)); } diff --git a/src/mathed/MathMacroTable.C b/src/mathed/MathMacroTable.C index 961235c2f2..3e3dd8ff54 100644 --- a/src/mathed/MathMacroTable.C +++ b/src/mathed/MathMacroTable.C @@ -41,7 +41,7 @@ MacroData::MacroData() MacroData::MacroData(docstring const & def, int numargs, docstring const & disp, string const & requires) - : def_(def), numargs_(numargs), disp_(disp), requires_(requires) + : def_(def), numargs_(numargs), disp_(disp), requires_(requires), lockCount_(0) {} diff --git a/src/mathed/MathMacroTable.h b/src/mathed/MathMacroTable.h index f6e2db77aa..e05a4938be 100644 --- a/src/mathed/MathMacroTable.h +++ b/src/mathed/MathMacroTable.h @@ -4,7 +4,7 @@ * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * - * \author André Pönitz + * \author AndrÈ Pˆnitz * * Full author contact details are available in file CREDITS. */ @@ -40,7 +40,14 @@ public: std::string requires() const { return requires_; } /// std::string & requires() { return requires_; } - + + /// + int lock() { return ++lockCount_; } + /// + bool locked() const { return lockCount_!=0; } + /// + void unlock() { --lockCount_; assert(lockCount_>=0); } + private: /// docstring def_; @@ -50,6 +57,8 @@ private: docstring disp_; /// std::string requires_; + /// + int lockCount_; }; diff --git a/src/mathed/MathMacroTemplate.C b/src/mathed/MathMacroTemplate.C index 2f6f8b4e79..99e58e8e8c 100644 --- a/src/mathed/MathMacroTemplate.C +++ b/src/mathed/MathMacroTemplate.C @@ -105,7 +105,7 @@ docstring MathMacroTemplate::name() const docstring MathMacroTemplate::prefix() const { - return bformat(_(" Macro: %1$s: "), name_); + return bformat(_(" Macro \\%1$s: "), name_); }