OK, here is a better formatted patch, preserving encoding etc. Thanks
for the feedback. The update is still being done in metrics() in the
same way that the macro expansion was being done previously. I have
changed it to cast away the const-ness rather than make cells_ mutable.
Assuming that the interface & function of the patch is acceptable I
will now implement a doDispatch(). In addition to changing the name
& number of arguments, I will also remove the expansion from metrics().
This will also negate the need for the mutable on MathMacro::tmpl_ and
MathMacro::expanded_.
If I rename a macro template, does it seem reasonable to automatically
update the name in all instantiations of that template?
thanks,
andrew
Index: text3.C =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/text3.C,v retrieving revision 1.323 diff -u -r1.323 text3.C --- text3.C 31 Dec 2005 11:40:32 -0000 1.323 +++ text3.C 27 Jan 2006 02:06:30 -0000 @@ -1254,10 +1254,10 @@ else { string s = cmd.argument; string const s1 = token(s, ' ', 1); - int const nargs = s1.empty() ? 0 : convert<int>(s1); +// int const nargs = s1.empty() ? 0 : convert<int>(s1); string const s2 = token(s, ' ', 2); string const type = s2.empty() ? "newcommand" : s2; - cur.insert(new MathMacroTemplate(token(s, ' ', 0), nargs, type)); + cur.insert(new MathMacroTemplate(token(s, ' ', 0), s1, type)); //cur.nextInset()->edit(cur, true); } break; Index: mathed/math_macro.C =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_macro.C,v retrieving revision 1.136 diff -u -r1.136 math_macro.C --- mathed/math_macro.C 5 Oct 2005 21:19:32 -0000 1.136 +++ mathed/math_macro.C 27 Jan 2006 02:06:39 -0000 @@ -59,22 +59,28 @@ { if (!MacroTable::globalMacros().has(name())) { mathed_string_dim(mi.base.font, "Unknown: " + name(), dim); - } else if (editing(mi.base.bv)) { - asArray(MacroTable::globalMacros().get(name()).def(), tmpl_); - LyXFont font = mi.base.font; - augmentFont(font, "lyxtex"); - tmpl_.metrics(mi, dim); - dim.wid += mathed_string_width(font, name()) + 10; - int ww = mathed_string_width(font, "#1: "); - for (idx_type i = 0; i < nargs(); ++i) { - MathArray const & c = cell(i); - c.metrics(mi); - dim.wid = max(dim.wid, c.width() + ww); - dim.des += c.height() + 10; - } } else { - MacroTable::globalMacros().get(name()).expand(cells_, expanded_); - expanded_.metrics(mi, dim); + const idx_type defArgs = static_cast<idx_type>(MacroTable::globalMacros().get(name()).numargs()); + if (nargs() < defArgs) + ((MathMacro*)this)->cells_.resize(defArgs); + + if (editing(mi.base.bv)) { + asArray(MacroTable::globalMacros().get(name()).def(), tmpl_); + LyXFont font = mi.base.font; + augmentFont(font, "lyxtex"); + tmpl_.metrics(mi, dim); + dim.wid += mathed_string_width(font, name()) + 10; + int ww = mathed_string_width(font, "#1: "); + for (idx_type i = 0; i < nargs(); ++i) { + MathArray const & c = cell(i); + c.metrics(mi); + dim.wid = max(dim.wid, c.width() + ww); + dim.des += c.height() + 10; + } + } else { + MacroTable::globalMacros().get(name()).expand(cells_, expanded_); + expanded_.metrics(mi, dim); + } } metricsMarkers2(dim); dim_ = dim; @@ -158,6 +164,8 @@ void MathMacro::updateExpansion() const { + if (MacroTable::globalMacros().has(name())) + MacroTable::globalMacros().get(name()).expand(cells_, expanded_); //expanded_.substitute(*this); } @@ -173,3 +181,4 @@ os << "Macro: " << name(); } + Index: mathed/math_macro.h =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_macro.h,v retrieving revision 1.103 diff -u -r1.103 math_macro.h --- mathed/math_macro.h 5 Oct 2005 21:19:32 -0000 1.103 +++ mathed/math_macro.h 27 Jan 2006 02:06:39 -0000 @@ -55,10 +55,14 @@ /// void infoize2(std::ostream &) const; -private: - virtual std::auto_ptr<InsetBase> doClone() const; + virtual MathMacro *asMacro() { return this; } + virtual MathMacro const *asMacro() const { return this; } + /// void updateExpansion() const; + +private: + virtual std::auto_ptr<InsetBase> doClone() const; /// void expand() const; Index: mathed/math_macrotable.C =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_macrotable.C,v retrieving revision 1.74 diff -u -r1.74 math_macrotable.C --- mathed/math_macrotable.C 24 Jul 2004 10:55:28 -0000 1.74 +++ mathed/math_macrotable.C 27 Jan 2006 02:06:40 -0000 @@ -15,6 +15,7 @@ #include "math_macroarg.h" #include "math_support.h" #include "math_sqrtinset.h" +#include "math_parser.h" #include "debug.h" #include "dociterator.h" @@ -42,15 +43,58 @@ {} -void MacroData::expand(vector<MathArray> const & args, MathArray & to) const +void MacroData::doExpand(vector<MathArray> const & args, MathArray const &from, MathArray & to) { - MathSqrtInset inset; // Hack. Any inset with a cell would do. - asArray(disp_.empty() ? def_ : disp_, inset.cell(0)); - //lyxerr << "MathData::expand: args: " << args << endl; - //lyxerr << "MathData::expand: ar: " << inset.cell(0) << endl; - for (DocIterator it = doc_iterator_begin(inset); it; it.forwardChar()) { + if (from.size() == 0) + return; + + MathSqrtInset inset; + inset.cell(0) = from; // Hack. Any inset with a cell would do. + +// for (size_t j=0; j<args.size(); j++) +// lyxerr << "MathData::expand: args(" << j << "): " << args[j] << endl; +// lyxerr << "MathData::expand: ar: " << inset.cell(0) << endl; + for (DocIterator it = doc_iterator_begin(inset); it; it.forwardChar()) { if (!it.nextInset()) continue; + + if (it.nextInset()->lyxCode() == InsetBase::MATHMACRO_CODE) { + MathMacroTemplate *p = static_cast<MathMacroTemplate*>(it.nextInset()); + + // first we parse the name, replacing any macro args + MathArray arNameRes; + doExpand(args, p->cell(0), arNameRes); + string parsedName = asString(arNameRes); + + MathArray arNumArgsRes; + doExpand(args, p->cell(1), arNumArgsRes); + string numArgs = asString(arNumArgsRes); + + // then we replace the definition and display + MathArray ar1; + doExpand(args, p->cell(2), ar1); + + MathArray ar2; + doExpand(args, p->cell(3), ar2); + + MathMacroTemplate *p1 = new MathMacroTemplate(parsedName, numArgs, "newcommand", ar1, ar2); + + // add the resulting macro to the global table + MacroTable::globalMacros().insert(p1->name(), p1->asMacroData()); + + // replace the one in the array with the new parsed version + MathArray tmpAr; + tmpAr.push_back(MathAtom(p1)); + + it.cell().erase(it.pos()); + DocIterator::pos_type oldSize = it.lastpos(); + it.cell().insert(it.pos(), tmpAr); + // attempt to skip the macro since it's already expanded + it.pos() = it.pos() + it.lastpos() - oldSize; + + continue; + } + if (it.nextInset()->lyxCode() != InsetBase::MATHMACROARG_CODE) continue; //it.cell().erase(it.pos()); @@ -58,13 +102,22 @@ size_t n = static_cast<MathMacroArgument*>(it.nextInset())->number(); if (n <= args.size()) { it.cell().erase(it.pos()); + DocIterator::pos_type oldSize = it.lastpos(); it.cell().insert(it.pos(), args[n - 1]); + // attempt to skip the argument value just inserted + it.pos() = it.pos() + it.lastpos() - oldSize; } } //lyxerr << "MathData::expand: res: " << inset.cell(0) << endl; to = inset.cell(0); } +void MacroData::expand(vector<MathArray> const & args, MathArray & to) const +{ + MathArray fromAr; + asArray(disp_.empty() ? def_ : disp_, fromAr); + doExpand(args, fromAr, to); +} // The global table. MacroTable & MacroTable::globalMacros() Index: mathed/math_macrotable.h =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_macrotable.h,v retrieving revision 1.23 diff -u -r1.23 math_macrotable.h --- mathed/math_macrotable.h 20 Apr 2004 08:51:15 -0000 1.23 +++ mathed/math_macrotable.h 27 Jan 2006 02:06:40 -0000 @@ -33,7 +33,9 @@ /// int numargs() const { return numargs_; } /// replace #1,#2,... by given MathAtom 0,1,.. - void expand(std::vector<MathArray> const & from, MathArray & to) const; + void expand(std::vector<MathArray> const & args, MathArray & to) const; + /// + static void doExpand(std::vector<MathArray> const & args, MathArray const &from, MathArray & to); private: /// Index: mathed/math_macrotemplate.C =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_macrotemplate.C,v retrieving revision 1.72 diff -u -r1.72 math_macrotemplate.C --- mathed/math_macrotemplate.C 24 Jan 2006 11:04:30 -0000 1.72 +++ mathed/math_macrotemplate.C 27 Jan 2006 02:06:41 -0000 @@ -15,6 +15,8 @@ #include "math_parser.h" #include "math_support.h" +#include "funcrequest.h" + #include "cursor.h" #include "debug.h" #include "gettext.h" @@ -25,6 +27,7 @@ #include "frontends/font_metrics.h" #include "support/lstrings.h" +#include "support/convert.h" using lyx::support::bformat; @@ -35,28 +38,45 @@ MathMacroTemplate::MathMacroTemplate() - : MathNestInset(2), numargs_(0), name_(), type_("newcommand") + : MathNestInset(4), type_("newcommand") { initMath(); } +/* MathMacroTemplate::MathMacroTemplate(string const & nm, int numargs, string const & type, MathArray const & ar1, MathArray const & ar2) - : MathNestInset(2), numargs_(numargs), name_(nm), type_(type) + : MathNestInset(4), type_(type) { initMath(); if (numargs_ > 9) lyxerr << "MathMacroTemplate::MathMacroTemplate: wrong # of arguments: " - << numargs_ << std::endl; - cell(0) = ar1; - cell(1) = ar2; + << numargs << std::endl; + + asArray(nm, cell(0)); + + asArray(convert<string>(numargs), cell(1)); + + cell(2) = ar1; + cell(3) = ar2; +} +*/ + +MathMacroTemplate::MathMacroTemplate(string const & nm, string const & numargs, + string const & type, MathArray const & ar1, MathArray const & ar2) + : MathNestInset(4), type_(type) +{ + asArray(nm, cell(0)); + asArray(numargs, cell(1)); + cell(2) = ar1; + cell(3) = ar2; } MathMacroTemplate::MathMacroTemplate(std::istream & is) - : MathNestInset(2), numargs_(0), name_() + : MathNestInset(4) { initMath(); @@ -85,25 +105,25 @@ int MathMacroTemplate::numargs() const { - return numargs_; + return convert<int>(asString(cell(1))); } void MathMacroTemplate::numargs(int numargs) { - numargs_ = numargs; + asArray(convert<string>(numargs), cell(1)); } string MathMacroTemplate::name() const { - return name_; + return asString(cell(0)); } string MathMacroTemplate::prefix() const { - return bformat(_(" Macro: %1$s: "), name_); + return string(" Macro: "); } @@ -111,10 +131,13 @@ { cell(0).metrics(mi); cell(1).metrics(mi); - dim.wid = cell(0).width() + cell(1).width() + 20 - + font_metrics::width(prefix(), mi.base.font); - dim.asc = std::max(cell(0).ascent(), cell(1).ascent()) + 7; - dim.des = std::max(cell(0).descent(), cell(1).descent()) + 7; + cell(2).metrics(mi); + cell(3).metrics(mi); + dim.wid = cell(0).width() + cell(1).width() + cell(2).width() + cell(3).width() + 26 + + font_metrics::width(prefix(), mi.base.font) + 8 + + font_metrics::width(":[]", mi.base.font); + dim.asc = std::max(cell(2).ascent(), cell(3).ascent()) + 7; + dim.des = std::max(cell(2).descent(), cell(3).descent()) + 7; dim_ = dim; } @@ -154,12 +177,27 @@ int const w0 = cell(0).width(); int const w1 = cell(1).width(); + int const w2 = cell(2).width(); + int const w3 = cell(3).width(); + cell(0).draw(pi, x + 2, y + 1); + x += w0 + 4; + + pi.pain.text(x, y, ": [", font); + x += font_metrics::width(": [", pi.base.font) + 2; + cell(1).draw(pi, x, y + 1); + x += w1 + 2; + pi.pain.text(x, y, "]", font); + x += font_metrics::width("]", pi.base.font); + + cell(2).draw(pi, x + 2, y + 1); + pi.pain.rectangle(x, y - dim_.ascent() + 3, + w2 + 4, dim_.height() - 6, LColor::mathline); + x += w2 + 6; + + cell(3).draw(pi, x + 2, y + 1); pi.pain.rectangle(x, y - dim_.ascent() + 3, - w0 + 4, dim_.height() - 6, LColor::mathline); - cell(1).draw(pi, x + 8 + w0, y + 1); - pi.pain.rectangle(x + w0 + 6, y - dim_.ascent() + 3, - w1 + 4, dim_.height() - 6, LColor::mathline); + w3 + 4, dim_.height() - 6, LColor::mathline); } @@ -186,17 +224,17 @@ void MathMacroTemplate::write(WriteStream & os) const { if (type_ == "def") { - os << "\\def\\" << name_.c_str(); - for (int i = 1; i <= numargs_; ++i) + os << "\\def\\" << name().c_str(); + for (int i = 1; i <= numargs(); ++i) os << '#' << i; } else { // newcommand or renewcommand - os << "\\" << type_.c_str() << "{\\" << name_.c_str() << '}'; - if (numargs_ > 0) - os << '[' << numargs_ << ']'; + os << "\\" << type_.c_str() << "{\\" << name().c_str() << '}'; + if (cell(1).size() > 0) + os << '[' << asString(cell(1)).c_str() << ']'; } - os << '{' << cell(0) << "}"; + os << '{' << cell(2) << "}"; if (os.latex()) { // writing .tex. done. @@ -204,12 +242,12 @@ } else { // writing .lyx, write special .tex export only if necessary if (!cell(1).empty()) - os << "\n{" << cell(1) << '}'; + os << "\n{" << cell(3) << '}'; } } MacroData MathMacroTemplate::asMacroData() const { - return MacroData(asString(cell(0)), numargs(), asString(cell(1))); + return MacroData(asString(cell(2)), numargs(), asString(cell(3))); } Index: mathed/math_macrotemplate.h =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_macrotemplate.h,v retrieving revision 1.47 diff -u -r1.47 math_macrotemplate.h --- mathed/math_macrotemplate.h 23 Nov 2004 23:04:51 -0000 1.47 +++ mathed/math_macrotemplate.h 27 Jan 2006 02:06:41 -0000 @@ -24,11 +24,17 @@ /// MathMacroTemplate(); /// - MathMacroTemplate(std::string const & name, int nargs, +/* MathMacroTemplate(std::string const & name, int nargs, std::string const & type, MathArray const & = MathArray(), MathArray const & = MathArray()); - /// +*/ + /// + MathMacroTemplate(std::string const & name, std::string const & nargs, + std::string const & type, + MathArray const & = MathArray(), + MathArray const & = MathArray()); + /// explicit MathMacroTemplate(std::istream & is); /// void edit(LCursor & cur, bool left); @@ -64,10 +70,6 @@ /// prefix in inset std::string prefix() const; - /// - int numargs_; - /// - std::string name_; /// newcommand or renewcommand or def std::string type_; }; Index: mathed/math_parser.C =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_parser.C,v retrieving revision 1.316 diff -u -r1.316 math_parser.C --- mathed/math_parser.C 8 Nov 2005 15:12:05 -0000 1.316 +++ mathed/math_parser.C 27 Jan 2006 02:06:45 -0000 @@ -856,38 +856,33 @@ { string const type = t.cs(); string name; - int nargs = 0; + string nargs; if (t.cs() == "def") { // get name name = getToken().cs(); // read parameter string pars; + int tmpArgC = 0; while (good() && nextToken().cat() != catBegin) { pars += getToken().cs(); - ++nargs; + ++tmpArgC; } - nargs /= 2; + tmpArgC /= 2; + if (tmpArgC > 0) + nargs = convert<string>(tmpArgC); //lyxerr << "read \\def parameter list '" << pars << "'" << endl; } else { // t.cs() == "newcommand" || t.cs() == "renewcommand" - if (getToken().cat() != catBegin) { - error("'{' in \\newcommand expected (1) "); + name = parse_verbatim_item(); + if (name.length() == 0) + { + error("<\\name> in \\newcommand expected"); return; } - - name = getToken().cs(); - - if (getToken().cat() != catEnd) { - error("'}' in \\newcommand expected"); - return; - } - - string const arg = getArg('[', ']'); - if (!arg.empty()) - nargs = convert<int>(arg); - + + nargs = getArg('[', ']'); } MathArray ar1; @@ -907,8 +902,7 @@ if (nextToken().cat() == catBegin) parse(ar2, FLAG_ITEM, MathInset::MATH_MODE); - cell->push_back(MathAtom(new MathMacroTemplate(name, nargs, type, - ar1, ar2))); + cell->push_back(MathAtom(new MathMacroTemplate(name, nargs, type, ar1, ar2))); } else if (t.cs() == "(") { @@ -1339,6 +1333,8 @@ parse(at.nucleus()->cell(i), FLAG_ITEM, m); skipSpaces(); } + if (at.nucleus()->asMacro()) + at.nucleus()->asMacro()->updateExpansion(); cell->push_back(at); } }