Here is the patch as it stands. I'd be interested in comments.
One issue is that I've made cells_ mutable, which seems dodgy.
Another is that the name & numArgs cells in macrotemplate are
just normal cells. I think they should be something that only
allows macroargs & string text or numbers to guarantee a legal
value is entered.
I've also attached a sample lyx file that demonstrates the patch.
Andrew
? dynamicMacro.diff ? lib.log ? mathed/dynamicMacro.diff Index: text3.C =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/text3.C,v retrieving revision 1.323 diff -r1.323 text3.C 7c7 < * \author Lars Gullik Bjønnes --- > * \author Lars Gullik Bjnnes 11c11 < * \author André Pönitz --- > * \author Andr�P�itz 1257c1257 < int const nargs = s1.empty() ? 0 : convert<int>(s1); --- > // int const nargs = s1.empty() ? 0 : convert<int>(s1); 1260c1260 < cur.insert(new MathMacroTemplate(token(s, ' ', 0), nargs, type)); --- > cur.insert(new MathMacroTemplate(token(s, ' ', 0), s1, type)); Index: mathed/math_macro.C =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_macro.C,v retrieving revision 1.136 diff -r1.136 math_macro.C 34c34,35 < {} --- > { > } 57d57 < 62,74d61 < } 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; < } 76,78c63,84 < 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) > 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); > } > } 160a167,168 > if (MacroTable::globalMacros().has(name())) > MacroTable::globalMacros().get(name()).expand(cells_, expanded_); 175a184 > Index: mathed/math_macro.h =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_macro.h,v retrieving revision 1.103 diff -r1.103 math_macro.h 57a58,62 > virtual MathMacro *asMacro() { return this; } > virtual MathMacro const *asMacro() const { return this; } > > void updateExpansion() const; > 61d65 < void updateExpansion() const; Index: mathed/math_macrotable.C =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_macrotable.C,v retrieving revision 1.74 diff -r1.74 math_macrotable.C 6c6 < * \author André Pönitz --- > * \author Andr�P�itz 21a22,23 > #include "math_parser.h" > 45c47 < void MacroData::expand(vector<MathArray> const & args, MathArray & to) const --- > void MacroData::doExpand(vector<MathArray> const & args, MathArray const &from, MathArray & to) 47,50c49,57 < 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; --- > if (from.size() == 0) > return; > > MathSqrtInset inset; > inset.cell(0) = from; // Hack. Any inset with a cell would do. > > // for (unsigned int j=0; j<args.size(); j++) > // lyxerr << "MathData::expand: args(" << j << "): " << args[j] << endl; > // lyxerr << "MathData::expand: ar: " << inset.cell(0) << endl; 52c59,60 < if (!it.nextInset()) --- > > if (!it.nextInset()) 54c62,102 < if (it.nextInset()->lyxCode() != InsetBase::MATHMACROARG_CODE) --- > > > 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) 61c109,112 < it.cell().insert(it.pos(), args[n - 1]); --- > 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; 67a119,124 > void MacroData::expand(vector<MathArray> const & args, MathArray & to) const > { > MathArray fromAr; > asArray(disp_.empty() ? def_ : disp_, fromAr); > doExpand(args, fromAr, to); > } Index: mathed/math_macrotable.h =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_macrotable.h,v retrieving revision 1.23 diff -r1.23 math_macrotable.h 36c36,37 < 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); Index: mathed/math_macrotemplate.C =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_macrotemplate.C,v retrieving revision 1.72 diff -r1.72 math_macrotemplate.C 6c6 < * \author André Pönitz --- > * \author Andr�P�itz 17a18,19 > #include "funcrequest.h" > 27a30 > #include "support/convert.h" 37a41,44 > <<<<<<< math_macrotemplate.C > : MathNestInset(4), type_("newcommand") > {} > ======= 41a49 > >>>>>>> 1.72 44c52 < MathMacroTemplate::MathMacroTemplate(string const & nm, int numargs, --- > /*MathMacroTemplate::MathMacroTemplate(string const & nm, int numargs, 46c54 < : MathNestInset(2), numargs_(numargs), name_(nm), type_(type) --- > : MathNestInset(4), type_(type) 47a56,58 > <<<<<<< math_macrotemplate.C > if (numargs > 9) > ======= 50a62 > >>>>>>> 1.72 52,54c64,82 < << numargs_ << std::endl; < cell(0) = ar1; < cell(1) = ar2; --- > << numargs << std::endl; > > asArray(nm, cell(0)); > > asArray(string(1, '0' + 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; 59c87 < : MathNestInset(2), numargs_(0), name_() --- > : MathNestInset(4) 88c116 < return numargs_; --- > return convert<int>(asString(cell(1))); 94c122 < numargs_ = numargs; --- > asArray(string(1, '0' + numargs), cell(1)); 100c128 < return name_; --- > return asString(cell(0)); 106c134 < return bformat(_(" Macro: %1$s: "), name_); --- > return string(" Macro: "); 112,117c140,149 < 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(0).metrics(mi); > cell(1).metrics(mi); > 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.wid = cell(0).width() + cell(1).width() + 20 > dim.asc = std::max(cell(2).ascent(), cell(3).ascent()) + 7; > dim.des = std::max(cell(2).descent(), cell(3).descent()) + 7; 156a189,191 > int const w2 = cell(2).width(); > int const w3 = cell(3).width(); > 157a193,207 > 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); 159,162c209 < 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); 189,190c236,237 < os << "\\def\\" << name_.c_str(); < for (int i = 1; i <= numargs_; ++i) --- > os << "\\def\\" << name().c_str(); > for (int i = 1; i <= numargs(); ++i) 194,196c241,243 < 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() << ']'; 199c246 < os << '{' << cell(0) << "}"; --- > os << '{' << cell(2) << "}"; 207c254,268 < os << "\n{" << cell(1) << '}'; --- > os << "\n{" << cell(3) << '}'; > } > } > > void MathMacroTemplate::doDispatch(LCursor & cur, FuncRequest & cmd) > { > switch (cmd.action) { > case LFUN_FINISHED_LEFT: > case LFUN_FINISHED_RIGHT: > case LFUN_FINISHED_UP: > case LFUN_FINISHED_DOWN: > lyxerr << "lfun_finished" << endl; > break; > default: > break; 208a270 > MathNestInset::doDispatch(cur, cmd); 214c276 < 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 -r1.47 math_macrotemplate.h 8c8 < * \author André Pönitz --- > * \author Andr�P�itz 27c27 < MathMacroTemplate(std::string const & name, int nargs, --- > /* MathMacroTemplate(std::string const & name, int nargs, 31c31,37 < /// --- > */ > /// > MathMacroTemplate(std::string const & name, std::string const & nargs, > std::string const & type, > MathArray const & = MathArray(), > MathArray const & = MathArray()); > /// 61a68,70 > protected: > virtual void doDispatch(LCursor & cur, FuncRequest & cmd); > 67,70d75 < /// < int numargs_; < /// < std::string name_; Index: mathed/math_nestinset.h =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_nestinset.h,v retrieving revision 1.69 diff -r1.69 math_nestinset.h 128c128 < cells_type cells_; --- > mutable cells_type cells_; Index: mathed/math_parser.C =================================================================== RCS file: /var/cvs/lyx/lyx-devel/src/mathed/math_parser.C,v retrieving revision 1.316 diff -r1.316 math_parser.C 6c6 < * \author André Pönitz --- > * \author Andr�P�itz 858a859 > string arg; 875,885c876,878 < if (getToken().cat() != catBegin) { < error("'{' in \\newcommand expected (1) "); < return; < } < < name = getToken().cs(); < < if (getToken().cat() != catEnd) { < error("'}' in \\newcommand expected"); < return; < } --- > name = parse_verbatim_item(); > if (name.length() == 0) > error("Invalid name in \\newcommand \n"); 887,889c880 < string const arg = getArg('[', ']'); < if (!arg.empty()) < nargs = convert<int>(arg); --- > arg = getArg('[', ']'); 910c901 < cell->push_back(MathAtom(new MathMacroTemplate(name, nargs, type, --- > cell->push_back(MathAtom(new MathMacroTemplate(name, arg, type, 1317a1309 > lyxerr << "at1 " << at << endl; 1340c1332 < skipSpaces(); --- > skipSpaces(); 1341a1334,1336 > if (at.nucleus()->asMacro()) > at.nucleus()->asMacro()->updateExpansion(); > lyxerr << "at2 " << at << endl;
newfile1.lyx
Description: newfile1.lyx