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
