mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-23 05:25:26 +00:00
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
This commit is contained in:
parent
8874db5f22
commit
71e8668375
@ -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; }
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
{}
|
||||
|
||||
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -105,7 +105,7 @@ docstring MathMacroTemplate::name() const
|
||||
|
||||
docstring MathMacroTemplate::prefix() const
|
||||
{
|
||||
return bformat(_(" Macro: %1$s: "), name_);
|
||||
return bformat(_(" Macro \\%1$s: "), name_);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user