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 "DispatchResult.h"
32 #include "FuncRequest.h"
33 #include "FuncStatus.h"
37 #include "frontends/Painter.h"
39 #include "support/convert.h"
40 #include "support/debug.h"
41 #include "support/gettext.h"
42 #include "support/docstream.h"
43 #include "support/lstrings.h"
51 using support::bformat;
53 //////////////////////////////////////////////////////////////////////
55 class InsetLabelBox : public InsetMathNest {
58 InsetLabelBox(MathAtom const & atom, docstring label,
59 MathMacroTemplate const & parent, bool frame = false);
60 InsetLabelBox(docstring label, MathMacroTemplate const & parent,
63 void metrics(MetricsInfo & mi, Dimension & dim) const;
65 void draw(PainterInfo &, int x, int y) const;
69 MathMacroTemplate const & parent_;
71 Inset * clone() const;
73 docstring const label_;
79 InsetLabelBox::InsetLabelBox(MathAtom const & atom, docstring label,
80 MathMacroTemplate const & parent, bool frame)
81 : InsetMathNest(1), parent_(parent), label_(label), frame_(frame)
83 cell(0).insert(0, atom);
87 InsetLabelBox::InsetLabelBox(docstring label,
88 MathMacroTemplate const & parent, bool frame)
89 : InsetMathNest(1), parent_(parent), label_(label), frame_(frame)
94 Inset * InsetLabelBox::clone() const
96 return new InsetLabelBox(*this);
100 void InsetLabelBox::metrics(MetricsInfo & mi, Dimension & dim) const
103 cell(0).metrics(mi, dim);
112 // adjust to common height in main metrics phase
113 if (!parent_.premetrics()) {
114 dim.asc = max(dim.asc, parent_.commonLabelBoxAscent());
115 dim.des = max(dim.des, parent_.commonLabelBoxDescent());
119 if (parent_.editing(mi.base.bv) && label_.length() > 0) {
121 FontInfo font = sane_font;
122 font.setSize(FONT_SIZE_TINY);
123 font.setColor(Color_mathmacrolabel);
125 // make space for label and box
126 int lwid = mathed_string_width(font, label_);
129 math_font_max_dim(font, maxasc, maxdes);
131 dim.wid = max(dim.wid, lwid + 2);
133 // space for the label
134 if (!parent_.premetrics())
135 dim.des += maxasc + maxdes + 1;
140 void InsetLabelBox::draw(PainterInfo & pi, int x, int y) const
142 Dimension const dim = dimension(*pi.base.bv);
143 Dimension const cdim = cell(0).dimension(*pi.base.bv);
146 cell(0).draw(pi, x + (dim.wid - cdim.wid) / 2, y);
149 if (parent_.editing(pi.base.bv) && label_.length() > 0) {
151 FontInfo font = sane_font;
152 font.setSize(FONT_SIZE_TINY);
153 font.setColor(Color_mathmacrolabel);
155 // make space for label and box
156 int lwid = mathed_string_width(font, label_);
159 math_font_max_dim(font, maxasc, maxdes);
162 pi.pain.text(x + (dim.wid - lwid) / 2, y + dim.des - maxdes, label_, font);
164 pi.pain.text(x, y + dim.des - maxdes, label_, font);
168 int boxHeight = parent_.commonLabelBoxAscent() + parent_.commonLabelBoxDescent();
170 pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
171 dim.wid - 2, boxHeight - 2,
177 //////////////////////////////////////////////////////////////////////
179 class DisplayLabelBox : public InsetLabelBox {
182 DisplayLabelBox(MathAtom const & atom, docstring label,
183 MathMacroTemplate const & parent);
186 void metrics(MetricsInfo & mi, Dimension & dim) const;
188 void draw(PainterInfo &, int x, int y) const;
192 Inset * clone() const;
196 DisplayLabelBox::DisplayLabelBox(MathAtom const & atom,
198 MathMacroTemplate const & parent)
199 : InsetLabelBox(atom, label, parent, true)
205 Inset * DisplayLabelBox::clone() const
207 return new DisplayLabelBox(*this);
211 void DisplayLabelBox::metrics(MetricsInfo & mi, Dimension & dim) const
213 InsetLabelBox::metrics(mi, dim);
214 if (!parent_.editing(mi.base.bv)
215 && parent_.cell(parent_.displayIdx()).empty()) {
223 void DisplayLabelBox::draw(PainterInfo & pi, int x, int y) const
225 if (parent_.editing(pi.base.bv)
226 || !parent_.cell(parent_.displayIdx()).empty()) {
227 InsetLabelBox::draw(pi, x, y);
229 bool enabled = pi.pain.isDrawingEnabled();
230 pi.pain.setDrawingEnabled(false);
231 InsetLabelBox::draw(pi, x, y);
232 pi.pain.setDrawingEnabled(enabled);
237 //////////////////////////////////////////////////////////////////////
239 class InsetMathWrapper : public InsetMath {
242 InsetMathWrapper(MathData const * value) : value_(value) {}
244 void metrics(MetricsInfo & mi, Dimension & dim) const;
246 void draw(PainterInfo &, int x, int y) const;
250 Inset * clone() const;
252 MathData const * value_;
256 Inset * InsetMathWrapper::clone() const
258 return new InsetMathWrapper(*this);
262 void InsetMathWrapper::metrics(MetricsInfo & mi, Dimension & dim) const
264 value_->metrics(mi, dim);
265 //metricsMarkers2(dim);
269 void InsetMathWrapper::draw(PainterInfo & pi, int x, int y) const
271 value_->draw(pi, x, y);
272 //drawMarkers(pi, x, y);
276 ///////////////////////////////////////////////////////////////////////
278 class InsetNameWrapper : public InsetMathWrapper {
281 InsetNameWrapper(MathData const * value, MathMacroTemplate const & parent);
283 void metrics(MetricsInfo & mi, Dimension & dim) const;
285 void draw(PainterInfo &, int x, int y) const;
289 MathMacroTemplate const & parent_;
291 Inset * clone() const;
295 InsetNameWrapper::InsetNameWrapper(MathData const * value,
296 MathMacroTemplate const & parent)
297 : InsetMathWrapper(value), parent_(parent)
302 Inset * InsetNameWrapper::clone() const
304 return new InsetNameWrapper(*this);
308 void InsetNameWrapper::metrics(MetricsInfo & mi, Dimension & dim) const
310 InsetMathWrapper::metrics(mi, dim);
311 dim.wid += mathed_string_width(mi.base.font, from_ascii("\\"));
315 void InsetNameWrapper::draw(PainterInfo & pi, int x, int y) const
318 PainterInfo namepi = pi;
319 if (parent_.validMacro())
320 namepi.base.font.setColor(Color_latex);
322 namepi.base.font.setColor(Color_error);
325 pi.pain.text(x, y, from_ascii("\\"), namepi.base.font);
326 x += mathed_string_width(namepi.base.font, from_ascii("\\"));
329 InsetMathWrapper::draw(namepi, x, y);
333 ///////////////////////////////////////////////////////////////////////
336 MathMacroTemplate::MathMacroTemplate()
337 : InsetMathNest(3), numargs_(0), optionals_(0),
338 type_(MacroTypeNewcommand), lookOutdated_(true)
344 MathMacroTemplate::MathMacroTemplate(docstring const & name, int numargs,
345 int optionals, MacroType type,
346 vector<MathData> const & optionalValues,
347 MathData const & def, MathData const & display)
348 : InsetMathNest(optionals + 3), numargs_(numargs),
349 optionals_(optionals), optionalValues_(optionalValues),
350 type_(type), lookOutdated_(true)
355 lyxerr << "MathMacroTemplate::MathMacroTemplate: wrong # of arguments: "
358 asArray(name, cell(0));
359 optionalValues_.resize(9);
360 for (int i = 0; i < optionals_; ++i)
361 cell(optIdx(i)) = optionalValues_[i];
362 cell(defIdx()) = def;
363 cell(displayIdx()) = display;
369 MathMacroTemplate::MathMacroTemplate(docstring const & str)
370 : InsetMathNest(3), numargs_(0), optionals_(0),
371 type_(MacroTypeNewcommand), lookOutdated_(true)
376 mathed_parse_cell(ar, str);
377 if (ar.size() != 1 || !ar[0]->asMacroTemplate()) {
378 lyxerr << "Cannot read macro from '" << ar << "'" << endl;
379 asArray(from_ascii("invalidmacro"), cell(0));
380 // FIXME: The macro template does not make sense after this.
381 // The whole parsing should not be in a constructor which
382 // has no chance to report failure.
385 operator=( *(ar[0]->asMacroTemplate()) );
391 Inset * MathMacroTemplate::clone() const
393 MathMacroTemplate * inset = new MathMacroTemplate(*this);
394 // the parent pointers of the proxy insets above will point to
395 // to the old template. Hence, the look must be updated.
401 docstring MathMacroTemplate::name() const
403 return asString(cell(0));
407 void MathMacroTemplate::updateToContext(MacroContext const & mc) const
409 redefinition_ = mc.get(name()) != 0;
413 void MathMacroTemplate::updateLook() const
415 lookOutdated_ = true;
419 void MathMacroTemplate::createLook() const
424 look_.push_back(MathAtom(new InsetLabelBox(_("Name"), *this, false)));
425 MathData & nameData = look_[look_.size() - 1].nucleus()->cell(0);
426 nameData.push_back(MathAtom(new InsetNameWrapper(&cell(0), *this)));
430 if (optionals_ > 0) {
431 look_.push_back(MathAtom(new InsetLabelBox(_("optional"), *this, false)));
432 MathData & optData = look_[look_.size() - 1].nucleus()->cell(0);
434 for (; i < optionals_; ++i) {
435 optData.push_back(MathAtom(new InsetMathChar('[')));
436 optData.push_back(MathAtom(new InsetMathWrapper(&cell(1 + i))));
437 optData.push_back(MathAtom(new InsetMathChar(']')));
442 for (; i < numargs_; ++i) {
444 arg.push_back(MathAtom(new MathMacroArgument(i + 1)));
445 look_.push_back(MathAtom(new InsetMathBrace(arg)));
449 look_.push_back(MathAtom(new InsetMathChar(':')));
450 look_.push_back(MathAtom(new InsetMathChar('=')));
453 look_.push_back(MathAtom(
454 new InsetLabelBox(MathAtom(
455 new InsetMathWrapper(&cell(defIdx()))), _("TeX"), *this, true)));
458 look_.push_back(MathAtom(
459 new DisplayLabelBox(MathAtom(
460 new InsetMathWrapper(&cell(displayIdx()))), _("LyX"), *this)));
464 void MathMacroTemplate::metrics(MetricsInfo & mi, Dimension & dim) const
466 FontSetChanger dummy1(mi.base, from_ascii("mathnormal"));
467 StyleChanger dummy2(mi.base, LM_ST_TEXT);
470 MacroData const * macro = 0;
472 macro = mi.macrocontext.get(name());
474 // updateToContext() - avoids another lookup
475 redefinition_ = macro != 0;
480 lookOutdated_ = false;
484 /// metrics for inset contents
488 // first phase, premetric:
490 look_.metrics(mi, dim);
491 labelBoxAscent_ = dim.asc;
492 labelBoxDescent_ = dim.des;
494 // second phase, main metric:
496 look_.metrics(mi, dim);
505 setDimCache(mi, dim);
509 void MathMacroTemplate::draw(PainterInfo & pi, int x, int y) const
511 FontSetChanger dummy1(pi.base, from_ascii("mathnormal"));
512 StyleChanger dummy2(pi.base, LM_ST_TEXT);
514 setPosCache(pi, x, y);
515 Dimension const dim = dimension(*pi.base.bv);
518 int const a = y - dim.asc + 1;
519 int const w = dim.wid - 2;
520 int const h = dim.height() - 2;
521 pi.pain.rectangle(x, a, w, h, Color_mathframe);
523 // just to be sure: set some dummy values for coord cache
524 for (idx_type i = 0; i < nargs(); ++i) {
525 cell(i).setXY(*pi.base.bv, x, y);
529 look_.draw(pi, x + 3, y);
533 void MathMacroTemplate::edit(Cursor & cur, bool front, EntryDirection entry_from)
536 cur.updateFlags(Update::Force);
537 InsetMathNest::edit(cur, front, entry_from);
541 bool MathMacroTemplate::notifyCursorLeaves(Cursor & cur)
544 cur.updateFlags(Update::Force);
545 return InsetMathNest::notifyCursorLeaves(cur);
549 void MathMacroTemplate::removeArguments(Cursor & cur, int from, int to) {
550 for (DocIterator it = doc_iterator_begin(*this); it; it.forwardChar()) {
553 if (it.nextInset()->lyxCode() != MATHMACROARG_CODE)
555 MathMacroArgument * arg = static_cast<MathMacroArgument*>(it.nextInset());
556 int n = arg->number() - 1;
557 if (from <= n && n <= to) {
558 int cellSlice = cur.find(it.cell());
559 if (cellSlice != -1 && cur[cellSlice].pos() > it.pos())
560 --cur[cellSlice].pos();
562 it.cell().erase(it.pos());
570 void MathMacroTemplate::shiftArguments(size_t from, int by) {
571 for (DocIterator it = doc_iterator_begin(*this); it; it.forwardChar()) {
574 if (it.nextInset()->lyxCode() != MATHMACROARG_CODE)
576 MathMacroArgument * arg = static_cast<MathMacroArgument*>(it.nextInset());
577 if (arg->number() >= from + 1)
578 arg->setNumber(arg->number() + by);
585 // FIXME: factorize those functions here with a functional style, maybe using Boost's function
588 void fixMacroInstancesAddRemove(Cursor const & from, docstring const & name, int n, bool insert) {
591 for (; dit; dit.forwardPos()) {
592 // only until a macro is redefined
593 if (dit.inset().lyxCode() == MATHMACRO_CODE) {
594 MathMacroTemplate const & macroTemplate
595 = static_cast<MathMacroTemplate const &>(dit.inset());
596 if (macroTemplate.name() == name)
600 // in front of macro instance?
601 Inset * inset = dit.nextInset();
604 InsetMath * insetMath = inset->asInsetMath();
608 MathMacro * macro = insetMath->asMacro();
609 if (macro && macro->name() == name && macro->folded()) {
610 // found macro instance
612 macro->insertArgument(n);
614 macro->removeArgument(n);
620 void fixMacroInstancesOptional(Cursor const & from, docstring const & name, int optionals) {
623 for (; dit; dit.forwardPos()) {
624 // only until a macro is redefined
625 if (dit.inset().lyxCode() == MATHMACRO_CODE) {
626 MathMacroTemplate const & macroTemplate
627 = static_cast<MathMacroTemplate const &>(dit.inset());
628 if (macroTemplate.name() == name)
632 // in front of macro instance?
633 Inset * inset = dit.nextInset();
636 InsetMath * insetMath = inset->asInsetMath();
639 MathMacro * macro = insetMath->asMacro();
640 if (macro && macro->name() == name && macro->folded()) {
641 // found macro instance
642 macro->setOptionals(optionals);
649 void fixMacroInstancesFunctional(Cursor const & from,
650 docstring const & name, F & fix) {
653 for (; dit; dit.forwardPos()) {
654 // only until a macro is redefined
655 if (dit.inset().lyxCode() == MATHMACRO_CODE) {
656 MathMacroTemplate const & macroTemplate
657 = static_cast<MathMacroTemplate const &>(dit.inset());
658 if (macroTemplate.name() == name)
662 // in front of macro instance?
663 Inset * inset = dit.nextInset();
666 InsetMath * insetMath = inset->asInsetMath();
669 MathMacro * macro = insetMath->asMacro();
670 if (macro && macro->name() == name && macro->folded())
676 void MathMacroTemplate::insertParameter(Cursor & cur, int pos, bool greedy)
678 if (pos <= numargs_ && pos >= optionals_ && numargs_ < 9) {
680 shiftArguments(pos, 1);
683 cell(defIdx()).push_back(MathAtom(new MathMacroArgument(pos + 1)));
684 if (!cell(displayIdx()).empty())
685 cell(displayIdx()).push_back(MathAtom(new MathMacroArgument(pos + 1)));
689 dit.leaveInset(*this);
690 // TODO: this was dit.forwardPosNoDescend before. Check that this is the same
691 dit.top().forwardPos();
693 // fix macro instances
694 fixMacroInstancesAddRemove(dit, name(), pos, true);
702 void MathMacroTemplate::removeParameter(Cursor & cur, int pos, bool greedy)
704 if (pos < numargs_ && pos >= 0) {
706 removeArguments(cur, pos, pos);
707 shiftArguments(pos + 1, -1);
709 // removed optional parameter?
710 if (pos < optionals_) {
712 optionalValues_[pos] = cell(optIdx(pos));
713 cells_.erase(cells_.begin() + optIdx(pos));
716 int macroSlice = cur.find(this);
717 if (macroSlice != -1) {
718 if (cur[macroSlice].idx() == optIdx(pos)) {
719 cur.cutOff(macroSlice);
720 cur[macroSlice].idx() = 1;
721 cur[macroSlice].pos() = 0;
722 } else if (cur[macroSlice].idx() > optIdx(pos))
723 --cur[macroSlice].idx();
728 // fix macro instances
729 //boost::function<void(MathMacro *)> fix = _1->insertArgument(n);
730 //fixMacroInstancesFunctional(dit, name(), fix);
732 dit.leaveInset(*this);
733 // TODO: this was dit.forwardPosNoDescend before. Check that this is the same
734 dit.top().forwardPos();
735 fixMacroInstancesAddRemove(dit, name(), pos, false);
743 void MathMacroTemplate::makeOptional(Cursor & cur) {
744 if (numargs_ > 0 && optionals_ < numargs_) {
746 cells_.insert(cells_.begin() + optIdx(optionals_ - 1), optionalValues_[optionals_ - 1]);
748 int macroSlice = cur.find(this);
749 if (macroSlice != -1 && cur[macroSlice].idx() >= optIdx(optionals_ - 1))
750 ++cur[macroSlice].idx();
752 // fix macro instances
754 dit.leaveInset(*this);
755 // TODO: this was dit.forwardPosNoDescend before. Check that this is the same
756 dit.top().forwardPos();
757 fixMacroInstancesOptional(dit, name(), optionals_);
764 void MathMacroTemplate::makeNonOptional(Cursor & cur) {
765 if (numargs_ > 0 && optionals_ > 0) {
768 // store default value for later if the use changes his mind
769 optionalValues_[optionals_] = cell(optIdx(optionals_));
770 cells_.erase(cells_.begin() + optIdx(optionals_));
773 int macroSlice = cur.find(this);
774 if (macroSlice != -1) {
775 if (cur[macroSlice].idx() > optIdx(optionals_))
776 --cur[macroSlice].idx();
777 else if (cur[macroSlice].idx() == optIdx(optionals_)) {
778 cur.cutOff(macroSlice);
779 cur[macroSlice].idx() = optIdx(optionals_);
780 cur[macroSlice].pos() = 0;
784 // fix macro instances
786 dit.leaveInset(*this);
787 // TODO: this was dit.forwardPosNoDescend before. Check that this is the same
788 dit.top().forwardPos();
789 fixMacroInstancesOptional(dit, name(), optionals_);
796 void MathMacroTemplate::doDispatch(Cursor & cur, FuncRequest & cmd)
798 string const arg = to_utf8(cmd.argument());
799 switch (cmd.action) {
801 case LFUN_MATH_MACRO_ADD_PARAM:
803 cur.recordUndoFullDocument();
804 size_t pos = numargs_;
806 pos = (size_t)convert<int>(arg) - 1; // it is checked for >=0 in getStatus
807 insertParameter(cur, pos);
812 case LFUN_MATH_MACRO_REMOVE_PARAM:
814 cur.recordUndoFullDocument();
815 size_t pos = numargs_ - 1;
817 pos = (size_t)convert<int>(arg) - 1; // it is checked for >=0 in getStatus
818 removeParameter(cur, pos);
822 case LFUN_MATH_MACRO_APPEND_GREEDY_PARAM:
824 cur.recordUndoFullDocument();
825 insertParameter(cur, numargs_, true);
829 case LFUN_MATH_MACRO_REMOVE_GREEDY_PARAM:
831 cur.recordUndoFullDocument();
832 removeParameter(cur, numargs_ - 1, true);
836 case LFUN_MATH_MACRO_MAKE_OPTIONAL:
837 cur.recordUndoFullDocument();
841 case LFUN_MATH_MACRO_MAKE_NONOPTIONAL:
842 cur.recordUndoFullDocument();
843 makeNonOptional(cur);
846 case LFUN_MATH_MACRO_ADD_OPTIONAL_PARAM:
848 cur.recordUndoFullDocument();
849 insertParameter(cur, optionals_);
854 case LFUN_MATH_MACRO_REMOVE_OPTIONAL_PARAM:
855 if (optionals_ > 0) {
856 cur.recordUndoFullDocument();
857 removeParameter(cur, optionals_ - 1);
860 case LFUN_MATH_MACRO_ADD_GREEDY_OPTIONAL_PARAM:
861 if (numargs_ == optionals_) {
862 cur.recordUndoFullDocument();
863 insertParameter(cur, 0, true);
869 InsetMathNest::doDispatch(cur, cmd);
875 bool MathMacroTemplate::getStatus(Cursor & /*cur*/, FuncRequest const & cmd,
876 FuncStatus & flag) const
879 string const arg = to_utf8(cmd.argument());
880 switch (cmd.action) {
881 case LFUN_MATH_MACRO_ADD_PARAM: {
882 int num = numargs_ + 1;
884 num = convert<int>(arg);
885 bool on = (num >= optionals_
886 && numargs_ < 9 && num <= numargs_ + 1);
891 case LFUN_MATH_MACRO_APPEND_GREEDY_PARAM:
892 flag.enabled(numargs_ < 9);
895 case LFUN_MATH_MACRO_REMOVE_PARAM: {
898 num = convert<int>(arg);
899 flag.enabled(num >= 1 && num <= numargs_);
903 case LFUN_MATH_MACRO_MAKE_OPTIONAL:
904 flag.enabled(numargs_ > 0
905 && optionals_ < numargs_
906 && type_ != MacroTypeDef);
909 case LFUN_MATH_MACRO_MAKE_NONOPTIONAL:
910 flag.enabled(optionals_ > 0
911 && type_ != MacroTypeDef);
914 case LFUN_MATH_MACRO_ADD_OPTIONAL_PARAM:
915 flag.enabled(numargs_ < 9);
918 case LFUN_MATH_MACRO_REMOVE_OPTIONAL_PARAM:
919 flag.enabled(optionals_ > 0);
922 case LFUN_MATH_MACRO_ADD_GREEDY_OPTIONAL_PARAM:
923 flag.enabled(numargs_ == 0
924 && type_ != MacroTypeDef);
927 case LFUN_IN_MATHMACROTEMPLATE:
939 void MathMacroTemplate::read(Buffer const &, Lexer & lex)
942 mathed_parse_cell(ar, lex.getStream());
943 if (ar.size() != 1 || !ar[0]->asMacroTemplate()) {
944 lyxerr << "Cannot read macro from '" << ar << "'" << endl;
945 lyxerr << "Read: " << to_utf8(asString(ar)) << endl;
948 operator=( *(ar[0]->asMacroTemplate()) );
954 void MathMacroTemplate::write(Buffer const &, ostream & os) const
956 odocstringstream oss;
957 WriteStream wi(oss, false, false);
958 oss << "FormulaMacro\n";
960 os << to_utf8(oss.str());
964 void MathMacroTemplate::write(WriteStream & os) const
970 void MathMacroTemplate::write(WriteStream & os, bool overwriteRedefinition) const
972 // newcommand or renewcommand
973 if (os.latex() && optionals_ > 1)
974 os << "\\newlyxcommand";
976 if (redefinition_ && !overwriteRedefinition)
977 os << "\\renewcommand";
979 os << "\\newcommand";
981 os << "{\\" << name().c_str() << '}';
983 os << '[' << numargs_ << ']';
986 for (int i = 0; i < optionals_; ++i) {
987 docstring optValue = asString(cell(optIdx(i)));
988 if (optValue.find(']') != docstring::npos)
989 os << "[{" << cell(optIdx(i)) << "}]";
991 os << "[" << cell(optIdx(i)) << "]";
994 os << "{" << cell(defIdx()) << "}";
997 // writing .tex. done.
1000 // writing .lyx, write special .tex export only if necessary
1001 if (!cell(displayIdx()).empty())
1002 os << "\n{" << cell(displayIdx()) << '}';
1007 int MathMacroTemplate::plaintext(Buffer const & buf, odocstream & os,
1008 OutputParams const &) const
1010 static docstring const str = '[' + buf.B_("math macro") + ']';
1017 bool MathMacroTemplate::validName() const
1019 docstring n = name();
1025 // converting back and force doesn't swallow anything?
1028 if (asString(ma) != n)
1031 // valid characters?
1032 for (size_t i = 0; i < n.size(); ++i) {
1033 if (!(n[i] >= 'a' && n[i] <= 'z') &&
1034 !(n[i] >= 'A' && n[i] <= 'Z'))
1042 bool MathMacroTemplate::validMacro() const
1048 bool MathMacroTemplate::fixNameAndCheckIfValid()
1050 // check all the characters/insets in the name cell
1052 MathData & data = cell(0);
1053 while (i < data.size()) {
1054 InsetMathChar const * cinset = data[i]->asCharInset();
1056 // valid character in [a-zA-Z]?
1057 char_type c = cinset->getChar();
1058 if ((c >= 'a' && c <= 'z')
1059 || (c >= 'A' && c <= 'Z')) {
1069 // now it should be valid if anything in the name survived
1070 return data.size() > 0;
1074 void MathMacroTemplate::validate(LaTeXFeatures & features) const
1076 if (optionals_ > 1) {
1077 features.require("newlyxcommand");
1081 void MathMacroTemplate::getDefaults(vector<docstring> & defaults) const
1083 defaults.resize(numargs_);
1084 for (int i = 0; i < optionals_; ++i)
1085 defaults[i] = asString(cell(optIdx(i)));
1089 docstring MathMacroTemplate::definition() const
1091 return asString(cell(defIdx()));
1095 docstring MathMacroTemplate::displayDefinition() const
1097 return asString(cell(displayIdx()));
1101 size_t MathMacroTemplate::numArgs() const
1107 size_t MathMacroTemplate::numOptionals() const
1113 void MathMacroTemplate::infoize(odocstream & os) const
1115 os << "Math Macro: \\" << name();