#include "InsetMathMacro.h"
#include "InsetMathChar.h"
+#include "InsetMathScript.h"
#include "MathCompletionList.h"
#include "MathExtern.h"
#include "MathFactory.h"
asArray(def, def_);
}
///
+ void setBuffer(Buffer & buffer)
+ {
+ Inset::setBuffer(buffer);
+ def_.setBuffer(buffer);
+ }
+ ///
void setOwner(InsetMathMacro * mathMacro) { mathMacro_ = mathMacro; }
///
InsetMathMacro const * owner() { return mathMacro_; }
void afterDraw(PainterInfo const & pi) const
{
if (mathMacro_->editMetrics(pi.base.bv))
- pi.pain.enterMonochromeMode(Color_mathbg, Color_mathmacroblend);
+ pi.pain.enterMonochromeMode(Color_mathmacroblend);
}
///
void metrics(MetricsInfo &, Dimension &) const {
expanded_(buf), definition_(buf), attachedArgsNum_(0),
optionals_(0), nextFoldMode_(true), macroBackup_(buf),
macro_(0), needsUpdate_(false), isUpdating_(false),
- appetite_(9), nesting_(0)
+ appetite_(9), nesting_(0), limits_(AUTO_LIMITS)
{
}
/// Update the pointers to our owner of all expanded macros.
///
mutable std::map<BufferView const *, bool> editing_;
///
- std::string requires_;
+ std::string required_;
/// update macro representation
bool needsUpdate_;
///
size_t appetite_;
/// Level of nesting in macros (including this one)
int nesting_;
+ ///
+ Limits limits_;
};
return has_contents;
}
+
+/// Whether the inset allows \(no)limits
+bool InsetMathMacro::allowsLimitsChange() const
+{
+ // similar to the code in mathClass(), except that we search for
+ // the right-side class.
+ MathClass mc = MC_UNKNOWN;
+ if (MacroData const * m = macroBackup()) {
+ // If it is a global macro and is defined explicitly
+ if (m->symbol())
+ mc = string_to_class(m->symbol()->extra);
+ }
+ // Otherwise guess from the expanded macro
+ if (mc == MC_UNKNOWN)
+ mc = d->expanded_.lastMathClass();
+
+ return mc == MC_OP;
+}
+
+
+Limits InsetMathMacro::defaultLimits() const
+{
+ if (d->expanded_.empty())
+ return NO_LIMITS;
+ // Guess from the expanded macro
+ InsetMath const * in = d->expanded_.back().nucleus();
+ Limits const lim = in->limits() == AUTO_LIMITS
+ ? in->defaultLimits() : in->limits();
+ LATTEST(lim != AUTO_LIMITS);
+ return lim;
+}
+
+
+Limits InsetMathMacro::limits() const
+{
+ return d->limits_;
+}
+
+
+void InsetMathMacro::limits(Limits lim)
+{
+ d->limits_ = lim;
+}
+
+
void InsetMathMacro::beforeMetrics() const
{
d->macro_->lock();
void InsetMathMacro::beforeDraw(PainterInfo const & pi) const
{
if (d->editing_[pi.base.bv])
- pi.pain.enterMonochromeMode(Color_mathbg, Color_mathmacroblend);
+ pi.pain.enterMonochromeMode(Color_mathmacroblend);
}
d->nesting_ = nesting;
// update requires
- d->requires_ = d->macro_->requires();
+ d->required_ = d->macro_->required();
if (!d->needsUpdate_
// non-normal mode? We are done!
values[i].insert(0, MathAtom(proxy));
}
// expanding macro with the values
- // Only update the argument macros if anything was expanded, otherwise
- // we would get an endless loop (bug 9140). UpdateLocker does not work
- // in this case, since MacroData::expand() creates new InsetMathMacro
- // objects, so this would be a different recursion path than the one
- // protected by UpdateLocker.
- if (d->macro_->expand(values, d->expanded_)) {
+ // Only update the argument macros if anything was expanded or the LyX
+ // representation part does not contain the macro itself, otherwise we
+ // would get an endless loop (bugs 9140 and 11595). UpdateLocker does
+ // not work in this case, since MacroData::expand() creates new
+ // InsetMathMacro objects, so this would be a different recursion path
+ // than the one protected by UpdateLocker.
+ docstring const & display = d->macro_->display();
+ docstring const latexname = from_ascii("\\") + macroName();
+ bool const ret = d->macro_->expand(values, d->expanded_);
+ d->expanded_.setBuffer(buffer());
+ if (ret && !support::contains(display, latexname)) {
if (utype == OutputUpdate && !d->expanded_.empty())
d->expanded_.updateMacros(cur, mc, utype, nesting);
}
// get definition for list edit mode
- docstring const & display = d->macro_->display();
asArray(display.empty() ? d->macro_->definition() : display,
d->definition_, Parse::QUIET | Parse::MACRODEF);
}
pi.pain.text(x, y, from_ascii(":"), labelFont);
x += strw2;
- // draw paramter
+ // draw parameter
cell(i).draw(pi, x, y);
// next line
return false;*/
// valid characters?
- for (size_t i = 0; i<n.size(); ++i) {
- if (!(n[i] >= 'a' && n[i] <= 'z')
- && !(n[i] >= 'A' && n[i] <= 'Z')
- && n[i] != '*')
- return false;
+ if (n.size() > 1) {
+ for (size_t i = 0; i<n.size(); ++i) {
+ if (!(n[i] >= 'a' && n[i] <= 'z')
+ && !(n[i] >= 'A' && n[i] <= 'Z')
+ && n[i] != '*')
+ return false;
+ }
}
return true;
// instant preview is on for math, in which case we will be missing
// the corresponding requirements.
// In this case, we get the required info from the global macro table.
- if (!d->requires_.empty())
- features.require(d->requires_);
+ if (!d->required_.empty())
+ features.require(d->required_);
else if (!d->macro_) {
// Update requires for known global macros.
MacroData const * data = MacroTable::globalMacros().get(name());
- if (data && !data->requires().empty())
- features.require(data->requires());
+ if (data && !data->required().empty())
+ features.require(data->required());
}
if (name() == "binom")
// validate the cells and the definition
if (displayMode() == DISPLAY_NORMAL) {
- d->definition_.validate(features);
+ // Don't update requirements if the macro comes from
+ // the symbols file and has not been redefined.
+ MathWordList const & words = mathedWordList();
+ MathWordList::const_iterator it = words.find(name());
+ MacroNameSet macros;
+ buffer().listMacroNames(macros);
+ if (it == words.end() || it->second.inset != "macro"
+ || macros.find(name()) != macros.end()) {
+ d->definition_.validate(features);
+ }
InsetMathNest::validate(features);
}
}
// we should be ok to continue even if this fails.
LATTEST(d->macro_);
- // We may already be in the argument of a macro
- bool const inside_macro = os.insideMacro();
- os.insideMacro(true);
-
- // Enclose in braces to avoid latex errors with xargs if we have
- // optional arguments and are in the optional argument of a macro
- if (d->optionals_ && inside_macro)
- os << '{';
-
// Always protect macros in a fragile environment
if (os.fragile())
os << "\\protect";
// print out optionals
for (i=0; i < cells_.size() && i < emptyOptFrom; ++i) {
first = false;
- os << "[" << cell(i) << "]";
+ // For correctly parsing it when a document is reloaded, we
+ // need to enclose an optional argument in braces if it starts
+ // with a script inset with empty nucleus or ends with a
+ // delimiter-size-modifier macro (see #10497 and #11346).
+ // We also need to do that when the optional argument
+ // contains macros with optionals.
+ bool braced = false;
+ size_type last = cell(i).size() - 1;
+ if (cell(i).size() && cell(i)[last]->asUnknownInset()) {
+ latexkeys const * l = in_word_set(cell(i)[last]->name());
+ braced = (l && l->inset == "big");
+ } else if (cell(i).size() && cell(i)[0]->asScriptInset()) {
+ braced = cell(i)[0]->asScriptInset()->nuc().empty();
+ } else {
+ for (size_type j = 0; j < cell(i).size(); ++j) {
+ InsetMathMacro const * ma = cell(i)[j]->asMacro();
+ if (ma && ma->optionals()) {
+ braced = true;
+ break;
+ }
+ }
+ }
+ if (braced)
+ os << "[{" << cell(i) << "}]";
+ else
+ os << "[" << cell(i) << "]";
}
// skip the tailing empty optionals
first = false;
}
- // Close the opened brace or add space if there was no argument
- if (d->optionals_ && inside_macro)
- os << '}';
- else if (first)
+ // add space if there was no argument
+ if (first)
os.pendingSpace(true);
- os.insideMacro(inside_macro);
+ // write \(no)limits modifiers if relevant
+ writeLimits(os);
}
}
-void InsetMathMacro::mathmlize(MathStream & os) const
+void InsetMathMacro::mathmlize(MathStream & ms) const
{
// macro_ is 0 if this is an unknown macro
LATTEST(d->macro_ || d->displayMode_ != DISPLAY_NORMAL);
if (d->macro_) {
- docstring const xmlname = d->macro_->xmlname();
+ docstring const xmlname = (ms.xmlMode()) ? d->macro_->xmlname() : d->macro_->htmlname();
if (!xmlname.empty()) {
char const * type = d->macro_->MathMLtype();
- os << '<' << type << "> " << xmlname << " </"
- << type << '>';
+ ms << "<" << from_ascii(ms.namespacedTag(type)) << ">"
+ << xmlname
+ << "</" << from_ascii(ms.namespacedTag(type)) << ">";
return;
}
}
// this means that we do not recognize the macro
throw MathExportException();
}
- os << d->expanded_;
+ ms << d->expanded_;
}
// macro_ is 0 if this is an unknown macro
LATTEST(d->macro_ || d->displayMode_ != DISPLAY_NORMAL);
if (d->macro_) {
- docstring const xmlname = d->macro_->xmlname();
+ docstring const xmlname = d->macro_->htmlname();
if (!xmlname.empty()) {
os << ' ' << xmlname << ' ';
return;
return InsetMathNest::completionSupported(cur);
return lyxrc.completion_popup_math
- && displayMode() == DISPLAY_UNFOLDED
&& cur.bv().cursor().pos() == int(name().size());
}
return InsetMathNest::inlineCompletionSupported(cur);
return lyxrc.completion_inline_math
- && displayMode() == DISPLAY_UNFOLDED
&& cur.bv().cursor().pos() == int(name().size());
}
}
+void InsetMathMacro::setBuffer(Buffer & buffer)
+{
+ d->definition_.setBuffer(buffer);
+ InsetMathNest::setBuffer(buffer);
+}
+
} // namespace lyx