]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/InsetMathMacro.cpp
Preserve \inputencoding value when switching to non-TeX fonts.
[lyx.git] / src / mathed / InsetMathMacro.cpp
index d2d4a8bc5d24c86c0447e085eb64c84748578a45..5e72eecdc27850b4737e833593b420df9f9f4bdb 100644 (file)
@@ -15,6 +15,7 @@
 #include "InsetMathMacro.h"
 
 #include "InsetMathChar.h"
+#include "InsetMathScript.h"
 #include "MathCompletionList.h"
 #include "MathExtern.h"
 #include "MathFactory.h"
@@ -660,17 +661,20 @@ void InsetMathMacro::updateRepresentation(Cursor * cur, MacroContext const & mc,
                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);
 }
@@ -800,11 +804,13 @@ bool InsetMathMacro::validName() const
                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;
@@ -861,23 +867,15 @@ MathClass InsetMathMacro::mathClass() const
 
 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;
 }
 
@@ -1069,10 +1067,8 @@ bool InsetMathMacro::folded() const
 
 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) {
@@ -1086,15 +1082,6 @@ void InsetMathMacro::write(WriteStream & os) const
        // 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";
@@ -1114,7 +1101,32 @@ void InsetMathMacro::write(WriteStream & os) const
        // 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
@@ -1133,13 +1145,9 @@ void InsetMathMacro::write(WriteStream & os) const
                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);
 }
 
 
@@ -1328,4 +1336,10 @@ void InsetMathMacro::completionPosAndDim(Cursor const & cur, int & x, int & y,
 }
 
 
+void InsetMathMacro::setBuffer(Buffer & buffer)
+{
+       d->definition_.setBuffer(buffer);
+       InsetMathNest::setBuffer(buffer);
+}
+
 } // namespace lyx