#include "InsetMathMacro.h"
#include "InsetMathChar.h"
+#include "InsetMathScript.h"
#include "MathCompletionList.h"
#include "MathExtern.h"
#include "MathFactory.h"
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();
+ if (d->macro_->expand(values, d->expanded_)
+ && !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);
}
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;
InsetMath::mode_type InsetMathMacro::currentMode() const
{
- // There is no way to guess the mode of user defined macros, so they are
- // always assumed to be mathmode. Only the global macros defined in
- // lib/symbols may be textmode.
- mode_type mode = modeToEnsure();
- return (mode == UNDECIDED_MODE) ? MATH_MODE : mode;
-}
-
-
-InsetMath::mode_type InsetMathMacro::modeToEnsure() const
-{
- // User defined macros can be either text mode or math mode for output and
- // display. There is no way to guess. For global macros defined in
- // lib/symbols, we ensure textmode if flagged as such, otherwise we ensure
- // math mode.
- if (MacroData const * m = macroBackup())
- if (m->symbol())
- return (m->symbol()->extra == "textmode") ? TEXT_MODE : MATH_MODE;
+ // User defined macros are always assumed to be mathmode macros.
+ // Only the global macros defined in lib/symbols may be textmode.
+ if (MacroData const * m = macroBackup()) {
+ if (m->symbol() && m->symbol()->extra == "textmode")
+ return TEXT_MODE;
+ else
+ return MATH_MODE;
+ }
+ // Unknown macros are undecided.
return UNDECIDED_MODE;
}
void InsetMathMacro::write(WriteStream & os) const
{
- mode_type mode = modeToEnsure();
- bool textmode_macro = mode == TEXT_MODE;
- bool needs_mathmode = mode == MATH_MODE;
- MathEnsurer ensurer(os, needs_mathmode, true, textmode_macro);
+ mode_type mode = currentMode();
+ MathEnsurer ensurer(os, mode == MATH_MODE, true, mode == TEXT_MODE);
// non-normal mode
if (d->displayMode_ != DISPLAY_NORMAL) {
// 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);
}
}
+void InsetMathMacro::setBuffer(Buffer & buffer)
+{
+ d->definition_.setBuffer(buffer);
+ InsetMathNest::setBuffer(buffer);
+}
+
} // namespace lyx