2 * \file MathMacroTemplate.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
13 #include "MathMacroTemplate.h"
15 #include "DocIterator.h"
16 #include "LaTeXFeatures.h"
17 #include "InsetMathBrace.h"
18 #include "InsetMathChar.h"
19 #include "InsetMathSqrt.h"
20 #include "MathMacro.h"
21 #include "MathMacroArgument.h"
22 #include "MathStream.h"
23 #include "MathParser.h"
24 #include "MathSupport.h"
25 #include "MathMacroArgument.h"
28 #include "BufferView.h"
31 #include "support/debug.h"
32 #include "DispatchResult.h"
33 #include "FuncRequest.h"
34 #include "FuncStatus.h"
35 #include "support/gettext.h"
39 #include "frontends/FontMetrics.h"
40 #include "frontends/Painter.h"
42 #include "support/convert.h"
43 #include "support/docstream.h"
44 #include "support/lstrings.h"
46 #include "support/debug.h"
54 using support::bformat;
56 //////////////////////////////////////////////////////////////////////
58 class InsetLabelBox : public InsetMathNest {
61 InsetLabelBox(MathAtom const & atom, docstring label,
62 MathMacroTemplate const & parent, bool frame = false);
63 InsetLabelBox(docstring label, MathMacroTemplate const & parent,
66 void metrics(MetricsInfo & mi, Dimension & dim) const;
68 void draw(PainterInfo &, int x, int y) const;
72 MathMacroTemplate const & parent_;
74 Inset * clone() const;
76 docstring const label_;
82 InsetLabelBox::InsetLabelBox(MathAtom const & atom, docstring label,
83 MathMacroTemplate const & parent, bool frame)
84 : InsetMathNest(1), parent_(parent), label_(label), frame_(frame)
86 cell(0).insert(0, atom);
90 InsetLabelBox::InsetLabelBox(docstring label,
91 MathMacroTemplate const & parent, bool frame)
92 : InsetMathNest(1), parent_(parent), label_(label), frame_(frame)
97 Inset * InsetLabelBox::clone() const
99 return new InsetLabelBox(*this);
103 void InsetLabelBox::metrics(MetricsInfo & mi, Dimension & dim) const
106 cell(0).metrics(mi, dim);
115 // adjust to common height in main metrics phase
116 if (!parent_.premetrics()) {
117 dim.asc = max(dim.asc, parent_.commonLabelBoxAscent());
118 dim.des = max(dim.des, parent_.commonLabelBoxDescent());
122 if (parent_.editing(mi.base.bv) && label_.length() > 0) {
124 FontInfo font = sane_font;
125 font.setSize(FONT_SIZE_TINY);
126 font.setColor(Color_mathmacrolabel);
128 // make space for label and box
129 int lwid = mathed_string_width(font, label_);
132 math_font_max_dim(font, maxasc, maxdes);
134 dim.wid = max(dim.wid, lwid + 2);
136 // space for the label
137 if (!parent_.premetrics())
138 dim.des += maxasc + maxdes + 1;
141 setDimCache(mi, dim);
145 void InsetLabelBox::draw(PainterInfo & pi, int x, int y) const
147 Dimension const dim = dimension(*pi.base.bv);
148 Dimension const cdim = cell(0).dimension(*pi.base.bv);
151 cell(0).draw(pi, x + (dim.wid - cdim.wid) / 2, y);
154 if (parent_.editing(pi.base.bv) && label_.length() > 0) {
156 FontInfo font = sane_font;
157 font.setSize(FONT_SIZE_TINY);
158 font.setColor(Color_mathmacrolabel);
160 // make space for label and box
161 int lwid = mathed_string_width(font, label_);
164 math_font_max_dim(font, maxasc, maxdes);
167 pi.pain.text(x + (dim.wid - lwid) / 2, y + dim.des - maxdes, label_, font);
169 pi.pain.text(x, y + dim.des - maxdes, label_, font);
173 int boxHeight = parent_.commonLabelBoxAscent() + parent_.commonLabelBoxDescent();
175 pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
176 dim.wid - 2, boxHeight - 2,
182 //////////////////////////////////////////////////////////////////////
184 class DisplayLabelBox : public InsetLabelBox {
187 DisplayLabelBox(MathAtom const & atom, docstring label,
188 MathMacroTemplate const & parent);
191 void metrics(MetricsInfo & mi, Dimension & dim) const;
193 void draw(PainterInfo &, int x, int y) const;
197 Inset * clone() const;
201 DisplayLabelBox::DisplayLabelBox(MathAtom const & atom,
203 MathMacroTemplate const & parent)
204 : InsetLabelBox(atom, label, parent, true)
210 Inset * DisplayLabelBox::clone() const
212 return new DisplayLabelBox(*this);
216 void DisplayLabelBox::metrics(MetricsInfo & mi, Dimension & dim) const
218 InsetLabelBox::metrics(mi, dim);
219 if (!parent_.editing(mi.base.bv)
220 && parent_.cell(parent_.displayIdx()).empty()) {
224 setDimCache(mi, dim);
229 void DisplayLabelBox::draw(PainterInfo & pi, int x, int y) const
231 if (parent_.editing(pi.base.bv)
232 || !parent_.cell(parent_.displayIdx()).empty()) {
233 InsetLabelBox::draw(pi, x, y);
235 bool enabled = pi.pain.isDrawingEnabled();
236 pi.pain.setDrawingEnabled(false);
237 InsetLabelBox::draw(pi, x, y);
238 pi.pain.setDrawingEnabled(enabled);
243 //////////////////////////////////////////////////////////////////////
245 class InsetMathWrapper : public InsetMath {
248 InsetMathWrapper(MathData const * value) : value_(value) {}
250 void metrics(MetricsInfo & mi, Dimension & dim) const;
252 void draw(PainterInfo &, int x, int y) const;
256 Inset * clone() const;
258 MathData const * value_;
262 Inset * InsetMathWrapper::clone() const
264 return new InsetMathWrapper(*this);
268 void InsetMathWrapper::metrics(MetricsInfo & mi, Dimension & dim) const
270 value_->metrics(mi, dim);
271 //metricsMarkers2(dim);
275 void InsetMathWrapper::draw(PainterInfo & pi, int x, int y) const
277 value_->draw(pi, x, y);
278 //drawMarkers(pi, x, y);
282 ///////////////////////////////////////////////////////////////////////
284 class InsetNameWrapper : public InsetMathWrapper {
287 InsetNameWrapper(MathData const * value, MathMacroTemplate const & parent);
289 void metrics(MetricsInfo & mi, Dimension & dim) const;
291 void draw(PainterInfo &, int x, int y) const;
295 MathMacroTemplate const & parent_;
297 Inset * clone() const;
301 InsetNameWrapper::InsetNameWrapper(MathData const * value,
302 MathMacroTemplate const & parent)
303 : InsetMathWrapper(value), parent_(parent)
308 Inset * InsetNameWrapper::clone() const
310 return new InsetNameWrapper(*this);
314 void InsetNameWrapper::metrics(MetricsInfo & mi, Dimension & dim) const
316 InsetMathWrapper::metrics(mi, dim);
317 dim.wid += mathed_string_width(mi.base.font, from_ascii("\\"));
321 void InsetNameWrapper::draw(PainterInfo & pi, int x, int y) const
324 PainterInfo namepi = pi;
325 if (parent_.validMacro())
326 namepi.base.font.setColor(Color_latex);
328 namepi.base.font.setColor(Color_error);
331 pi.pain.text(x, y, from_ascii("\\"), namepi.base.font);
332 x += mathed_string_width(namepi.base.font, from_ascii("\\"));
335 InsetMathWrapper::draw(namepi, x, y);
339 ///////////////////////////////////////////////////////////////////////
342 MathMacroTemplate::MathMacroTemplate()
343 : InsetMathNest(3), numargs_(0), optionals_(0),
344 type_(MacroTypeNewcommand), lookOutdated_(true)
350 MathMacroTemplate::MathMacroTemplate(docstring const & name, int numargs,
351 int optionals, MacroType type,
352 vector<MathData> const & optionalValues,
353 MathData const & def, MathData const & display)
354 : InsetMathNest(optionals + 3), numargs_(numargs),
355 optionals_(optionals), optionalValues_(optionalValues),
356 type_(type), lookOutdated_(true)
361 lyxerr << "MathMacroTemplate::MathMacroTemplate: wrong # of arguments: "
364 asArray(name, cell(0));
365 optionalValues_.resize(9);
366 for (int i = 0; i < optionals_; ++i)
367 cell(optIdx(i)) = optionalValues_[i];
368 cell(defIdx()) = def;
369 cell(displayIdx()) = display;
375 MathMacroTemplate::MathMacroTemplate(docstring const & str)
376 : InsetMathNest(3), numargs_(0), optionals_(0),
377 type_(MacroTypeNewcommand), lookOutdated_(true)
382 mathed_parse_cell(ar, str);
383 if (ar.size() != 1 || !ar[0]->asMacroTemplate()) {
384 lyxerr << "Cannot read macro from '" << ar << "'" << endl;
385 asArray(from_ascii("invalidmacro"), cell(0));
386 // FIXME: The macro template does not make sense after this.
387 // The whole parsing should not be in a constructor which
388 // has no chance to report failure.
391 operator=( *(ar[0]->asMacroTemplate()) );
397 Inset * MathMacroTemplate::clone() const
399 return new MathMacroTemplate(*this);
403 docstring MathMacroTemplate::name() const
405 return asString(cell(0));
409 void MathMacroTemplate::updateToContext(MacroContext const & mc) const
411 redefinition_ = mc.get(name()) != 0;
415 void MathMacroTemplate::updateLook() const
417 lookOutdated_ = true;
421 void MathMacroTemplate::createLook() const
426 look_.push_back(MathAtom(new InsetLabelBox(_("Name"), *this, false)));
427 MathData & nameData = look_[look_.size() - 1].nucleus()->cell(0);
428 nameData.push_back(MathAtom(new InsetNameWrapper(&cell(0), *this)));
432 if (optionals_ > 0) {
433 look_.push_back(MathAtom(new InsetLabelBox(_("optional"), *this, false)));
434 MathData & optData = look_[look_.size() - 1].nucleus()->cell(0);
436 for (; i < optionals_; ++i) {
437 optData.push_back(MathAtom(new InsetMathChar('[')));
438 optData.push_back(MathAtom(new InsetMathWrapper(&cell(1 + i))));
439 optData.push_back(MathAtom(new InsetMathChar(']')));
444 for (; i < numargs_; ++i) {
446 arg.push_back(MathAtom(new MathMacroArgument(i + 1)));
447 look_.push_back(MathAtom(new InsetMathBrace(arg)));
451 look_.push_back(MathAtom(new InsetMathChar(':')));
452 look_.push_back(MathAtom(new InsetMathChar('=')));
455 look_.push_back(MathAtom(
456 new InsetLabelBox(MathAtom(
457 new InsetMathWrapper(&cell(defIdx()))), _("TeX"), *this, true)));
460 look_.push_back(MathAtom(
461 new DisplayLabelBox(MathAtom(
462 new InsetMathWrapper(&cell(displayIdx()))), _("LyX"), *this)));
466 void MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
468 FontSetChanger dummy1(mi.base, from_ascii("mathnormal"));
469 StyleChanger dummy2(mi.base, LM_ST_TEXT);
472 MacroData const * macro = 0;
474 macro = mi.macrocontext.get(name());
476 // updateToContext() - avoids another lookup
477 redefinition_ = macro != 0;
482 lookOutdated_ = false;
486 /// metrics for inset contents
490 // first phase, premetric:
492 look_.metrics(mi, dim);
493 labelBoxAscent_ = dim.asc;
494 labelBoxDescent_ = dim.des;
496 // second phase, main metric:
498 look_.metrics(mi, dim);
507 setDimCache(mi, dim);
511 void MathMacroTemplate::draw(PainterInfo & pi, int x, int y) const
513 FontSetChanger dummy1(pi.base, from_ascii("mathnormal"));
514 StyleChanger dummy2(pi.base, LM_ST_TEXT);
516 setPosCache(pi, x, y);
517 Dimension const dim = dimension(*pi.base.bv);
520 int const a = y - dim.asc + 1;
521 int const w = dim.wid - 2;
522 int const h = dim.height() - 2;
523 pi.pain.rectangle(x, a, w, h, Color_mathframe);
525 // just to be sure: set some dummy values for coord cache
526 for (idx_type i = 0; i < nargs(); ++i) {
527 cell(i).setXY(*pi.base.bv, x, y);
531 look_.draw(pi, x + 3, y);
535 void MathMacroTemplate::edit(Cursor & cur, bool left)
538 cur.updateFlags(Update::Force);
539 InsetMathNest::edit(cur, left);
543 bool MathMacroTemplate::notifyCursorLeaves(Cursor & cur)
546 cur.updateFlags(Update::Force);
547 return InsetMathNest::notifyCursorLeaves(cur);
551 void MathMacroTemplate::removeArguments(Cursor & cur, int from, int to) {
552 for (DocIterator it = doc_iterator_begin(*this); it; it.forwardChar()) {
555 if (it.nextInset()->lyxCode() != MATHMACROARG_CODE)
557 MathMacroArgument * arg = static_cast<MathMacroArgument*>(it.nextInset());
558 int n = arg->number() - 1;
559 if (from <= n && n <= to) {
560 int cellSlice = cur.find(it.cell());
561 if (cellSlice != -1 && cur[cellSlice].pos() > it.pos())
562 --cur[cellSlice].pos();
564 it.cell().erase(it.pos());
572 void MathMacroTemplate::shiftArguments(size_t from, int by) {
573 for (DocIterator it = doc_iterator_begin(*this); it; it.forwardChar()) {
576 if (it.nextInset()->lyxCode() != MATHMACROARG_CODE)
578 MathMacroArgument * arg = static_cast<MathMacroArgument*>(it.nextInset());
579 if (arg->number() >= from + 1)
580 arg->setNumber(arg->number() + by);
587 // FIXME: factorize those functions here with a functional style, maybe using Boost's function
590 void fixMacroInstancesAddRemove(Cursor const & from, docstring const & name, int n, bool insert) {
593 for (; dit; dit.forwardPos()) {
594 // only until a macro is redefined
595 if (dit.inset().lyxCode() == MATHMACRO_CODE) {
596 MathMacroTemplate const & macroTemplate
597 = static_cast<MathMacroTemplate const &>(dit.inset());
598 if (macroTemplate.name() == name)
602 // in front of macro instance?
603 Inset * inset = dit.nextInset();
606 InsetMath * insetMath = inset->asInsetMath();
610 MathMacro * macro = insetMath->asMacro();
611 if (macro && macro->name() == name && macro->folded()) {
612 // found macro instance
614 macro->insertArgument(n);
616 macro->removeArgument(n);
622 void fixMacroInstancesOptional(Cursor const & from, docstring const & name, int optionals) {
625 for (; dit; dit.forwardPos()) {
626 // only until a macro is redefined
627 if (dit.inset().lyxCode() == MATHMACRO_CODE) {
628 MathMacroTemplate const & macroTemplate
629 = static_cast<MathMacroTemplate const &>(dit.inset());
630 if (macroTemplate.name() == name)
634 // in front of macro instance?
635 Inset * inset = dit.nextInset();
638 InsetMath * insetMath = inset->asInsetMath();
641 MathMacro * macro = insetMath->asMacro();
642 if (macro && macro->name() == name && macro->folded()) {
643 // found macro instance
644 macro->setOptionals(optionals);
651 void fixMacroInstancesFunctional(Cursor const & from,
652 docstring const & name, F & fix) {
655 for (; dit; dit.forwardPos()) {
656 // only until a macro is redefined
657 if (dit.inset().lyxCode() == MATHMACRO_CODE) {
658 MathMacroTemplate const & macroTemplate
659 = static_cast<MathMacroTemplate const &>(dit.inset());
660 if (macroTemplate.name() == name)
664 // in front of macro instance?
665 Inset * inset = dit.nextInset();
668 InsetMath * insetMath = inset->asInsetMath();
671 MathMacro * macro = insetMath->asMacro();
672 if (macro && macro->name() == name && macro->folded())
678 void MathMacroTemplate::insertParameter(Cursor & cur, int pos, bool greedy)
680 if (pos <= numargs_ && pos >= optionals_ && numargs_ < 9) {
682 shiftArguments(pos, 1);
685 cell(defIdx()).push_back(MathAtom(new MathMacroArgument(pos + 1)));
686 if (!cell(displayIdx()).empty())
687 cell(displayIdx()).push_back(MathAtom(new MathMacroArgument(pos + 1)));
691 dit.leaveInset(*this);
692 // TODO: this was dit.forwardPosNoDescend before. Check that this is the same
693 dit.top().forwardPos();
695 // fix macro instances
696 fixMacroInstancesAddRemove(dit, name(), pos, true);
704 void MathMacroTemplate::removeParameter(Cursor & cur, int pos, bool greedy)
706 if (pos < numargs_ && pos >= 0) {
708 removeArguments(cur, pos, pos);
709 shiftArguments(pos + 1, -1);
711 // removed optional parameter?
712 if (pos < optionals_) {
714 optionalValues_[pos] = cell(optIdx(pos));
715 cells_.erase(cells_.begin() + optIdx(pos));
718 int macroSlice = cur.find(this);
719 if (macroSlice != -1) {
720 if (cur[macroSlice].idx() == optIdx(pos)) {
721 cur.cutOff(macroSlice);
722 cur[macroSlice].idx() = 1;
723 cur[macroSlice].pos() = 0;
724 } else if (cur[macroSlice].idx() > optIdx(pos))
725 --cur[macroSlice].idx();
730 // fix macro instances
731 //boost::function<void(MathMacro *)> fix = _1->insertArgument(n);
732 //fixMacroInstancesFunctional(dit, name(), fix);
734 dit.leaveInset(*this);
735 // TODO: this was dit.forwardPosNoDescend before. Check that this is the same
736 dit.top().forwardPos();
737 fixMacroInstancesAddRemove(dit, name(), pos, false);
745 void MathMacroTemplate::makeOptional(Cursor & cur) {
746 if (numargs_ > 0 && optionals_ < numargs_) {
748 cells_.insert(cells_.begin() + optIdx(optionals_ - 1), optionalValues_[optionals_ - 1]);
750 int macroSlice = cur.find(this);
751 if (macroSlice != -1 && cur[macroSlice].idx() >= optIdx(optionals_ - 1))
752 ++cur[macroSlice].idx();
754 // fix macro instances
756 dit.leaveInset(*this);
757 // TODO: this was dit.forwardPosNoDescend before. Check that this is the same
758 dit.top().forwardPos();
759 fixMacroInstancesOptional(dit, name(), optionals_);
766 void MathMacroTemplate::makeNonOptional(Cursor & cur) {
767 if (numargs_ > 0 && optionals_ > 0) {
770 // store default value for later if the use changes his mind
771 optionalValues_[optionals_] = cell(optIdx(optionals_));
772 cells_.erase(cells_.begin() + optIdx(optionals_));
775 int macroSlice = cur.find(this);
776 if (macroSlice != -1) {
777 if (cur[macroSlice].idx() > optIdx(optionals_))
778 --cur[macroSlice].idx();
779 else if (cur[macroSlice].idx() == optIdx(optionals_)) {
780 cur.cutOff(macroSlice);
781 cur[macroSlice].idx() = optIdx(optionals_);
782 cur[macroSlice].pos() = 0;
786 // fix macro instances
788 dit.leaveInset(*this);
789 // TODO: this was dit.forwardPosNoDescend before. Check that this is the same
790 dit.top().forwardPos();
791 fixMacroInstancesOptional(dit, name(), optionals_);
798 void MathMacroTemplate::doDispatch(Cursor & cur, FuncRequest & cmd)
800 string const arg = to_utf8(cmd.argument());
801 switch (cmd.action) {
803 case LFUN_MATH_MACRO_ADD_PARAM:
805 cur.recordUndoFullDocument();
806 size_t pos = numargs_;
808 pos = (size_t)convert<int>(arg) - 1; // it is checked for >=0 in getStatus
809 insertParameter(cur, pos);
814 case LFUN_MATH_MACRO_REMOVE_PARAM:
816 cur.recordUndoFullDocument();
817 size_t pos = numargs_ - 1;
819 pos = (size_t)convert<int>(arg) - 1; // it is checked for >=0 in getStatus
820 removeParameter(cur, pos);
824 case LFUN_MATH_MACRO_APPEND_GREEDY_PARAM:
826 cur.recordUndoFullDocument();
827 insertParameter(cur, numargs_, true);
831 case LFUN_MATH_MACRO_REMOVE_GREEDY_PARAM:
833 cur.recordUndoFullDocument();
834 removeParameter(cur, numargs_ - 1, true);
838 case LFUN_MATH_MACRO_MAKE_OPTIONAL:
839 cur.recordUndoFullDocument();
843 case LFUN_MATH_MACRO_MAKE_NONOPTIONAL:
844 cur.recordUndoFullDocument();
845 makeNonOptional(cur);
848 case LFUN_MATH_MACRO_ADD_OPTIONAL_PARAM:
850 cur.recordUndoFullDocument();
851 insertParameter(cur, optionals_);
856 case LFUN_MATH_MACRO_REMOVE_OPTIONAL_PARAM:
857 if (optionals_ > 0) {
858 cur.recordUndoFullDocument();
859 removeParameter(cur, optionals_ - 1);
862 case LFUN_MATH_MACRO_ADD_GREEDY_OPTIONAL_PARAM:
863 if (numargs_ == optionals_) {
864 cur.recordUndoFullDocument();
865 insertParameter(cur, 0, true);
871 InsetMathNest::doDispatch(cur, cmd);
877 bool MathMacroTemplate::getStatus(Cursor & /*cur*/, FuncRequest const & cmd,
878 FuncStatus & flag) const
881 string const arg = to_utf8(cmd.argument());
882 switch (cmd.action) {
883 case LFUN_MATH_MACRO_ADD_PARAM: {
884 int num = numargs_ + 1;
886 num = convert<int>(arg);
887 bool on = (num >= optionals_
888 && numargs_ < 9 && num <= numargs_ + 1);
893 case LFUN_MATH_MACRO_APPEND_GREEDY_PARAM:
894 flag.enabled(numargs_ < 9);
897 case LFUN_MATH_MACRO_REMOVE_PARAM: {
900 num = convert<int>(arg);
901 flag.enabled(num >= 1 && num <= numargs_);
905 case LFUN_MATH_MACRO_MAKE_OPTIONAL:
906 flag.enabled(numargs_ > 0
907 && optionals_ < numargs_
908 && type_ != MacroTypeDef);
911 case LFUN_MATH_MACRO_MAKE_NONOPTIONAL:
912 flag.enabled(optionals_ > 0
913 && type_ != MacroTypeDef);
916 case LFUN_MATH_MACRO_ADD_OPTIONAL_PARAM:
917 flag.enabled(numargs_ < 9);
920 case LFUN_MATH_MACRO_REMOVE_OPTIONAL_PARAM:
921 flag.enabled(optionals_ > 0);
924 case LFUN_MATH_MACRO_ADD_GREEDY_OPTIONAL_PARAM:
925 flag.enabled(numargs_ == 0
926 && type_ != MacroTypeDef);
929 case LFUN_IN_MATHMACROTEMPLATE:
941 void MathMacroTemplate::read(Buffer const &, Lexer & lex)
944 mathed_parse_cell(ar, lex.getStream());
945 if (ar.size() != 1 || !ar[0]->asMacroTemplate()) {
946 lyxerr << "Cannot read macro from '" << ar << "'" << endl;
947 lyxerr << "Read: " << to_utf8(asString(ar)) << endl;
950 operator=( *(ar[0]->asMacroTemplate()) );
956 void MathMacroTemplate::write(Buffer const &, ostream & os) const
958 odocstringstream oss;
959 WriteStream wi(oss, false, false);
960 oss << "FormulaMacro\n";
962 os << to_utf8(oss.str());
966 void MathMacroTemplate::write(WriteStream & os) const
972 void MathMacroTemplate::write(WriteStream & os, bool overwriteRedefinition) const
974 // newcommand or renewcommand
975 if (os.latex() && optionals_ > 1)
976 os << "\\newlyxcommand";
979 os << "\\renewcommand";
981 os << "\\newcommand";
983 os << "{\\" << name().c_str() << '}';
985 os << '[' << numargs_ << ']';
988 for (int i = 0; i < optionals_; ++i) {
989 docstring optValue = asString(cell(optIdx(i)));
990 if (optValue.find(']') != docstring::npos)
991 os << "[{" << cell(optIdx(i)) << "}]";
993 os << "[" << cell(optIdx(i)) << "]";
996 os << "{" << cell(defIdx()) << "}";
999 // writing .tex. done.
1002 // writing .lyx, write special .tex export only if necessary
1003 if (!cell(displayIdx()).empty())
1004 os << "\n{" << cell(displayIdx()) << '}';
1009 int MathMacroTemplate::plaintext(Buffer const & buf, odocstream & os,
1010 OutputParams const &) const
1012 static docstring const str = '[' + buf.B_("math macro") + ']';
1019 bool MathMacroTemplate::validName() const
1021 docstring n = name();
1027 // converting back and force doesn't swallow anything?
1030 if (asString(ma) != n)
1033 // valid characters?
1034 for (size_t i = 0; i < n.size(); ++i) {
1035 if (!(n[i] >= 'a' && n[i] <= 'z') &&
1036 !(n[i] >= 'A' && n[i] <= 'Z'))
1044 bool MathMacroTemplate::validMacro() const
1050 bool MathMacroTemplate::fixNameAndCheckIfValid()
1052 // check all the characters/insets in the name cell
1054 MathData & data = cell(0);
1055 while (i < data.size()) {
1056 InsetMathChar const * cinset = data[i]->asCharInset();
1058 // valid character in [a-zA-Z]?
1059 char_type c = cinset->getChar();
1060 if ((c >= 'a' && c <= 'z')
1061 || (c >= 'A' && c <= 'Z')) {
1071 // now it should be valid if anything in the name survived
1072 return data.size() > 0;
1076 void MathMacroTemplate::validate(LaTeXFeatures & features) const
1078 if (optionals_ > 1) {
1079 features.require("newlyxcommand");
1083 void MathMacroTemplate::getDefaults(vector<docstring> & defaults) const
1085 defaults.resize(numargs_);
1086 for (int i = 0; i < optionals_; ++i)
1087 defaults[i] = asString(cell(optIdx(i)));
1091 docstring MathMacroTemplate::definition() const
1093 return asString(cell(defIdx()));
1097 docstring MathMacroTemplate::displayDefinition() const
1099 return asString(cell(displayIdx()));
1103 size_t MathMacroTemplate::numArgs() const
1109 size_t MathMacroTemplate::numOptionals() const
1115 void MathMacroTemplate::infoize(odocstream & os) const
1117 os << "Math Macro: \\" << name();