]> git.lyx.org Git - features.git/commitdiff
Fix bug 1395 by Stefan Schimanski:
authorAbdelrazak Younes <younes@lyx.org>
Tue, 17 Apr 2007 13:15:00 +0000 (13:15 +0000)
committerAbdelrazak Younes <younes@lyx.org>
Tue, 17 Apr 2007 13:15:00 +0000 (13:15 +0000)
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
src/mathed/InsetMathBrace.h
src/mathed/InsetMathMacro.C
src/mathed/InsetMathMacro.h
src/mathed/MathData.C
src/mathed/MathData.h
src/mathed/MathFactory.C
src/mathed/MathMacroTable.C
src/mathed/MathMacroTable.h
src/mathed/MathMacroTemplate.C

index 6602d98b9caaf8f4ed946ab7eb948a39f5aca571..508f9af95d8d7c4c111464e20bbe60d32751ab80 100644 (file)
@@ -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; }
index 3d581dc023c23dce476cc557bdf476566e50b132..f7c399a9c75b226af95d8f0c5adbcc989f75a840 100644 (file)
@@ -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<InsetBase> doClone() const;
 };
index 43cbed7c315ab6e9bb8d1540c3f8d5bc6f7fcc8c..6db0b05e45f9c8fd0da6f4df842186f662fcf0f3 100644 (file)
@@ -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<InsetBase> doClone() const;
+       MathArray const * value_;
+};
+
+
+auto_ptr<InsetBase> MathMacroArgumentValue::doClone() const 
+{
+       return auto_ptr<InsetBase>(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<MathArray> 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<MathArray> &args)
+{
+       args = cells_;
+       cells_ = std::vector<MathArray>();
+}
+
+
+void MathMacro::attachArguments(std::vector<MathArray> 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();
-
 }
 
 
index cc2be0a014847f8fc718ee4d86fbeb8d6e27b1d7..a1d1144922d4b72516e2e5f43be386702691a504 100644 (file)
@@ -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<MathArray> &args);
+       ///
+       void attachArguments(std::vector<MathArray> const &args);
+       
        ///
        void validate(LaTeXFeatures &) const;
 
@@ -70,14 +78,10 @@ public:
 
 private:
        virtual std::auto_ptr<InsetBase> 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_;
index b2ef50fb97f9196f07827f7f880ba5b405ff6df7..70a256c70812a9af1c39042820e5b75171b495ee 100644 (file)
@@ -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<MathArray*>(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<MathArray> detachedArgs;
+                               macroInset->detachArguments( detachedArgs );
+                               
+                               // too many arguments in the macro inset?
+                               if (detachedArgs.size() > numargs) {
+                                       // insert overlap back as braces
+                                       std::vector<MathArray> 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);
index d3c916c28e4c797a90aa655527913bacec314911..a2ea8c837ed0e6c782069644816e4855311f22dd 100644 (file)
@@ -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;
index 62bcef30db3a579a06823e195289936c7e915c2c..2be23f6915926d5ebfbd589dfe96bffb38dea81e 100644 (file)
@@ -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));
 }
 
 
index 961235c2f28a426ebf37353679c170cac43a1f99..3e3dd8ff5453ac74ccc53f001f795673b089f7e6 100644 (file)
@@ -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)
 {}
 
 
index f6e2db77aa88bbb74ffb60fcaaaebceacbeaf831..e05a4938be853dd680c3022ab12981d73249881a 100644 (file)
@@ -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_;
 };
 
 
index 2f6f8b4e79e59a97f6a4d0746ada73d52e6e355f..99e58e8e8c85734e769398dd84928ddf9d3ac272 100644 (file)
@@ -105,7 +105,7 @@ docstring MathMacroTemplate::name() const
 
 docstring MathMacroTemplate::prefix() const
 {
-       return bformat(_(" Macro%1$s: "), name_);
+       return bformat(_(" Macro \\%1$s: "), name_);
 }