]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/MathParser.cpp
Routines for calculating numerical labels for BibTeX citations.
[lyx.git] / src / mathed / MathParser.cpp
index 32da4448a54c8a8fd924d7a7743bdc9df05d08e0..c57221a362644d9d3eb8f39871a821d1793009b8 100644 (file)
@@ -64,6 +64,8 @@ following hack as starting point to write some macros:
 #include "MathMacroArgument.h"
 #include "MathSupport.h"
 
+#include "Buffer.h"
+#include "BufferParams.h"
 #include "Encoding.h"
 #include "Lexer.h"
 
@@ -359,12 +361,12 @@ public:
        typedef  Parse::flags parse_mode;
 
        ///
-       Parser(Lexer & lex, parse_mode mode);
+       Parser(Lexer & lex, parse_mode mode, Buffer * buf);
        /// Only use this for reading from .lyx file format, for the reason
        /// see Parser::tokenize(istream &).
-       Parser(istream & is, parse_mode mode);
+       Parser(istream & is, parse_mode mode, Buffer * buf);
        ///
-       Parser(docstring const & str, parse_mode mode);
+       Parser(docstring const & str, parse_mode mode, Buffer * buf);
 
        ///
        bool parse(MathAtom & at);
@@ -432,26 +434,29 @@ private:
        parse_mode mode_;
        ///
        bool success_;
+       ///
+       Buffer * buffer_;
 };
 
 
-Parser::Parser(Lexer & lexer, parse_mode mode)
-       : lineno_(lexer.lineNumber()), pos_(0), mode_(mode), success_(true)
+Parser::Parser(Lexer & lexer, parse_mode mode, Buffer * buf)
+       : lineno_(lexer.lineNumber()), pos_(0), mode_(mode), success_(true),
+         buffer_(buf)
 {
        tokenize(lexer.getStream());
        lexer.eatLine();
 }
 
 
-Parser::Parser(istream & is, parse_mode mode)
-       : lineno_(0), pos_(0), mode_(mode), success_(true)
+Parser::Parser(istream & is, parse_mode mode, Buffer * buf)
+       : lineno_(0), pos_(0), mode_(mode), success_(true), buffer_(buf)
 {
        tokenize(is);
 }
 
 
-Parser::Parser(docstring const & str, parse_mode mode)
-       : lineno_(0), pos_(0), mode_(mode), success_(true)
+Parser::Parser(docstring const & str, parse_mode mode, Buffer * buf)
+       : lineno_(0), pos_(0), mode_(mode), success_(true), buffer_(buf)
 {
        tokenize(str);
 }
@@ -671,12 +676,12 @@ void Parser::error(string const & msg)
 bool Parser::parse(MathAtom & at)
 {
        skipSpaces();
-       MathData ar;
+       MathData ar(buffer_);
        parse(ar, false, InsetMath::UNDECIDED_MODE);
        if (ar.size() != 1 || ar.front()->getType() == hullNone) {
                if (!(mode_ & Parse::QUIET))
                        lyxerr << "unusual contents found: " << ar << endl;
-               at = MathAtom(new InsetMathPar(ar));
+               at = MathAtom(new InsetMathPar(buffer_, ar));
                //if (at->nargs() > 0)
                //      at.nucleus()->cell(0) = ar;
                //else
@@ -727,7 +732,7 @@ docstring Parser::parse_verbatim_item()
 
 MathData Parser::parse(unsigned flags, mode_type mode)
 {
-       MathData ar;
+       MathData ar(buffer_);
        parse(ar, flags, mode);
        return ar;
 }
@@ -735,7 +740,7 @@ MathData Parser::parse(unsigned flags, mode_type mode)
 
 bool Parser::parse(MathData & array, unsigned flags, mode_type mode)
 {
-       InsetMathGrid grid(1, 1);
+       InsetMathGrid grid(buffer_, 1, 1);
        parse1(grid, flags, mode, false);
        array = grid.cell(0);
        return success_;
@@ -756,6 +761,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
        InsetMathGrid::row_type cellrow = 0;
        InsetMathGrid::col_type cellcol = 0;
        MathData * cell = &grid.cell(grid.index(cellrow, cellcol));
+       Buffer * buf = buffer_;
 
        if (grid.asHullInset())
                grid.asHullInset()->numbered(cellrow, numbered);
@@ -825,18 +831,18 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                Token const & n = getToken();
                                if (n.cat() == catMath) {
                                        // TeX's $$...$$ syntax for displayed math
-                                       cell->push_back(MathAtom(new InsetMathHull(hullEquation)));
+                                       cell->push_back(MathAtom(new InsetMathHull(buf, hullEquation)));
                                        parse2(cell->back(), FLAG_SIMPLE, InsetMath::MATH_MODE, false);
                                        getToken(); // skip the second '$' token
                                } else {
                                        // simple $...$  stuff
                                        putback();
                                        if (mode == InsetMath::UNDECIDED_MODE) {
-                                               cell->push_back(MathAtom(new InsetMathHull(hullSimple)));
+                                               cell->push_back(MathAtom(new InsetMathHull(buf, hullSimple)));
                                                parse2(cell->back(), FLAG_SIMPLE, InsetMath::MATH_MODE, false);
                                        } else {
                                                // Don't create nested math hulls (bug #5392)
-                                               cell->push_back(MathAtom(new InsetMathEnsureMath));
+                                               cell->push_back(MathAtom(new InsetMathEnsureMath(buf)));
                                                parse(cell->back().nucleus()->cell(0), FLAG_SIMPLE, InsetMath::MATH_MODE);
                                        }
                                }
@@ -907,14 +913,14 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        // we need no new script inset if the last thing was a scriptinset,
                        // which has that script already not the same script already
                        if (!cell->size())
-                               cell->push_back(MathAtom(new InsetMathScript(up)));
+                               cell->push_back(MathAtom(new InsetMathScript(buf, up)));
                        else if (cell->back()->asScriptInset() &&
                                        !cell->back()->asScriptInset()->has(up))
                                cell->back().nucleus()->asScriptInset()->ensure(up);
                        else if (cell->back()->asScriptInset())
-                               cell->push_back(MathAtom(new InsetMathScript(up)));
+                               cell->push_back(MathAtom(new InsetMathScript(buf, up)));
                        else
-                               cell->back() = MathAtom(new InsetMathScript(cell->back(), up));
+                               cell->back() = MathAtom(new InsetMathScript(buf, cell->back(), up));
                        InsetMathScript * p = cell->back().nucleus()->asScriptInset();
                        // special handling of {}-bases
                        // Here we could remove the brace inset for things
@@ -948,7 +954,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                            || mode == InsetMath::TEXT_MODE) {
                                cell->push_back(MathAtom(new InsetMathChar(c)));
                        } else {
-                               MathAtom at = createInsetMath("text");
+                               MathAtom at = createInsetMath("text", buf);
                                at.nucleus()->cell(0).push_back(MathAtom(new InsetMathChar(c)));
                                while (nextToken().cat() == catOther
                                       && !isAsciiOrMathAlpha(nextToken().character())) {
@@ -967,7 +973,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        break;
                                s += t.asString();
                        }
-                       cell->push_back(MathAtom(new InsetMathComment(s)));
+                       cell->push_back(MathAtom(new InsetMathComment(buf, s)));
                        skipSpaces();
                }
 
@@ -1007,8 +1013,12 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        if (nextToken().cat() == catBegin)
                                parse(display, FLAG_ITEM, InsetMath::MATH_MODE);
                        
-                       cell->push_back(MathAtom(new MathMacroTemplate(name, nargs,
-                              0, MacroTypeDef, vector<MathData>(), def, display)));
+                       cell->push_back(MathAtom(new MathMacroTemplate(buf,
+                               name, nargs, 0, MacroTypeDef,
+                               vector<MathData>(), def, display)));
+
+                       if (buf && (mode_ & Parse::TRACKMACRO))
+                               buf->usermacros.insert(name);
                }
                
                else if (t.cs() == "newcommand" ||
@@ -1051,9 +1061,12 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        if (nextToken().cat() == catBegin)
                                parse(display, FLAG_ITEM, InsetMath::MATH_MODE);
                        
-                       cell->push_back(MathAtom(new MathMacroTemplate(name, nargs,
-                               optionals, MacroTypeNewcommand, optionalValues, def, display)));
-                       
+                       cell->push_back(MathAtom(new MathMacroTemplate(buf,
+                               name, nargs, optionals, MacroTypeNewcommand,
+                               optionalValues, def, display)));
+
+                       if (buf && (mode_ & Parse::TRACKMACRO))
+                               buf->usermacros.insert(name);
                }
                
                else if (t.cs() == "newcommandx" ||
@@ -1169,9 +1182,12 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        if (nextToken().cat() == catBegin)
                                parse(display, FLAG_ITEM, InsetMath::MATH_MODE);
 
-                       cell->push_back(MathAtom(new MathMacroTemplate(name, nargs,
-                               optionals, MacroTypeNewcommandx, optionalValues, def, 
-                               display)));
+                       cell->push_back(MathAtom(new MathMacroTemplate(buf,
+                               name, nargs, optionals, MacroTypeNewcommandx,
+                               optionalValues, def, display)));
+
+                       if (buf && (mode_ & Parse::TRACKMACRO))
+                               buf->usermacros.insert(name);
                }
 
                else if (t.cs() == "(") {
@@ -1179,7 +1195,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                error("bad math environment");
                                break;
                        }
-                       cell->push_back(MathAtom(new InsetMathHull(hullSimple)));
+                       cell->push_back(MathAtom(new InsetMathHull(buf, hullSimple)));
                        parse2(cell->back(), FLAG_SIMPLE2, InsetMath::MATH_MODE, false);
                }
 
@@ -1188,7 +1204,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                error("bad math environment");
                                break;
                        }
-                       cell->push_back(MathAtom(new InsetMathHull(hullEquation)));
+                       cell->push_back(MathAtom(new InsetMathHull(buf, hullEquation)));
                        parse2(cell->back(), FLAG_EQUATION, InsetMath::MATH_MODE, false);
                }
 
@@ -1315,11 +1331,11 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        MathData ar;
                        parse(ar, FLAG_OPTION, mode);
                        if (ar.size()) {
-                               cell->push_back(MathAtom(new InsetMathRoot));
+                               cell->push_back(MathAtom(new InsetMathRoot(buf)));
                                cell->back().nucleus()->cell(0) = ar;
                                parse(cell->back().nucleus()->cell(1), FLAG_ITEM, mode);
                        } else {
-                               cell->push_back(MathAtom(new InsetMathSqrt));
+                               cell->push_back(MathAtom(new InsetMathSqrt(buf)));
                                parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode);
                        }
                }
@@ -1329,11 +1345,11 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        MathData ar;
                        parse(ar, FLAG_OPTION, mode);
                        if (ar.size()) {
-                               cell->push_back(MathAtom(new InsetMathFrac(InsetMathFrac::UNIT)));
+                               cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::UNIT)));
                                cell->back().nucleus()->cell(0) = ar;
                                parse(cell->back().nucleus()->cell(1), FLAG_ITEM, mode);
                        } else {
-                               cell->push_back(MathAtom(new InsetMathFrac(InsetMathFrac::UNIT, 1)));
+                               cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::UNIT, 1)));
                                parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode);
                        }
                }
@@ -1343,10 +1359,10 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        MathData ar;
                        parse(ar, FLAG_OPTION, mode);
                        if (ar.size()) {
-                               cell->push_back(MathAtom(new InsetMathFrac(InsetMathFrac::UNITFRAC, 3)));
+                               cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::UNITFRAC, 3)));
                                cell->back().nucleus()->cell(2) = ar;
                        } else {
-                               cell->push_back(MathAtom(new InsetMathFrac(InsetMathFrac::UNITFRAC)));
+                               cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::UNITFRAC)));
                        }
                        parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode);
                        parse(cell->back().nucleus()->cell(1), FLAG_ITEM, mode);
@@ -1357,11 +1373,11 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        docstring const arg = getArg('[', ']');
                        //lyxerr << "got so far: '" << arg << "'" << endl;                              
                                if (arg == "l")
-                                       cell->push_back(MathAtom(new InsetMathFrac(InsetMathFrac::CFRACLEFT)));
+                                       cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRACLEFT)));
                                else if (arg == "r")
-                                       cell->push_back(MathAtom(new InsetMathFrac(InsetMathFrac::CFRACRIGHT)));
+                                       cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRACRIGHT)));
                                else if (arg.empty() || arg == "c")
-                                       cell->push_back(MathAtom(new InsetMathFrac(InsetMathFrac::CFRAC)));
+                                       cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRAC)));
                                else {
                                        error("found invalid optional argument");
                                        break;
@@ -1371,14 +1387,14 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                }
 
                else if (t.cs() == "xrightarrow" || t.cs() == "xleftarrow") {
-                       cell->push_back(createInsetMath(t.cs()));
+                       cell->push_back(createInsetMath(t.cs(), buf));
                        parse(cell->back().nucleus()->cell(1), FLAG_OPTION, mode);
                        parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode);
                }
 
                else if (t.cs() == "ref" || t.cs() == "eqref" || t.cs() == "prettyref"
                          || t.cs() == "pageref" || t.cs() == "vpageref" || t.cs() == "vref") {
-                       cell->push_back(MathAtom(new InsetMathRef(t.cs())));
+                       cell->push_back(MathAtom(new InsetMathRef(buf, t.cs())));
                        parse(cell->back().nucleus()->cell(1), FLAG_OPTION, mode);
                        parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode);
                }
@@ -1397,7 +1413,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        skipSpaces();
                        Token const & tr = getToken();
                        docstring const r = tr.cs() == "|" ? from_ascii("Vert") : tr.asString();
-                       cell->push_back(MathAtom(new InsetMathDelim(l, r, ar)));
+                       cell->push_back(MathAtom(new InsetMathDelim(buf, l, r, ar)));
                }
 
                else if (t.cs() == "right") {
@@ -1415,7 +1431,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        if (name == "array" || name == "subarray") {
                                docstring const valign = parse_verbatim_option() + 'c';
                                docstring const halign = parse_verbatim_item();
-                               cell->push_back(MathAtom(new InsetMathArray(name,
+                               cell->push_back(MathAtom(new InsetMathArray(buf, name,
                                        InsetMathGrid::guessColumns(halign), 1, (char)valign[0], halign)));
                                parse2(cell->back(), FLAG_END, mode, false);
                        }
@@ -1423,13 +1439,13 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        else if (name == "tabular") {
                                docstring const valign = parse_verbatim_option() + 'c';
                                docstring const halign = parse_verbatim_item();
-                               cell->push_back(MathAtom(new InsetMathTabular(name,
+                               cell->push_back(MathAtom(new InsetMathTabular(buf, name,
                                        InsetMathGrid::guessColumns(halign), 1, (char)valign[0], halign)));
                                parse2(cell->back(), FLAG_END, InsetMath::TEXT_MODE, false);
                        }
 
                        else if (name == "split" || name == "cases") {
-                               cell->push_back(createInsetMath(name));
+                               cell->push_back(createInsetMath(name, buf));
                                parse2(cell->back(), FLAG_END, mode, false);
                        }
 
@@ -1437,7 +1453,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                docstring const valign = parse_verbatim_option() + 'c';
                                // ignore this for a while
                                getArg('{', '}');
-                               cell->push_back(MathAtom(new InsetMathSplit(name, (char)valign[0])));
+                               cell->push_back(MathAtom(new InsetMathSplit(buf, name, (char)valign[0])));
                                parse2(cell->back(), FLAG_END, mode, false);
                        }
 
@@ -1446,7 +1462,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        error("bad math environment");
                                        break;
                                }
-                               cell->push_back(MathAtom(new InsetMathHull(hullSimple)));
+                               cell->push_back(MathAtom(new InsetMathHull(buf, hullSimple)));
                                parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, true);
                        }
 
@@ -1456,7 +1472,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        error("bad math environment");
                                        break;
                                }
-                               cell->push_back(MathAtom(new InsetMathHull(hullEquation)));
+                               cell->push_back(MathAtom(new InsetMathHull(buf, hullEquation)));
                                parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, (name == "equation"));
                        }
 
@@ -1465,7 +1481,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        error("bad math environment");
                                        break;
                                }
-                               cell->push_back(MathAtom(new InsetMathHull(hullEqnArray)));
+                               cell->push_back(MathAtom(new InsetMathHull(buf, hullEqnArray)));
                                parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name));
                        }
 
@@ -1474,7 +1490,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        error("bad math environment");
                                        break;
                                }
-                               cell->push_back(MathAtom(new InsetMathHull(hullAlign)));
+                               cell->push_back(MathAtom(new InsetMathHull(buf, hullAlign)));
                                parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name));
                        }
 
@@ -1483,7 +1499,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        error("bad math environment");
                                        break;
                                }
-                               cell->push_back(MathAtom(new InsetMathHull(hullFlAlign)));
+                               cell->push_back(MathAtom(new InsetMathHull(buf, hullFlAlign)));
                                parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name));
                        }
 
@@ -1494,7 +1510,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                }
                                // ignore this for a while
                                getArg('{', '}');
-                               cell->push_back(MathAtom(new InsetMathHull(hullAlignAt)));
+                               cell->push_back(MathAtom(new InsetMathHull(buf, hullAlignAt)));
                                parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name));
                        }
 
@@ -1505,7 +1521,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                }
                                // ignore this for a while
                                getArg('{', '}');
-                               cell->push_back(MathAtom(new InsetMathHull(hullXAlignAt)));
+                               cell->push_back(MathAtom(new InsetMathHull(buf, hullXAlignAt)));
                                parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name));
                        }
 
@@ -1516,7 +1532,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                }
                                // ignore this for a while
                                getArg('{', '}');
-                               cell->push_back(MathAtom(new InsetMathHull(hullXXAlignAt)));
+                               cell->push_back(MathAtom(new InsetMathHull(buf, hullXXAlignAt)));
                                parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name));
                        }
 
@@ -1525,7 +1541,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        error("bad math environment");
                                        break;
                                }
-                               cell->push_back(MathAtom(new InsetMathHull(hullMultline)));
+                               cell->push_back(MathAtom(new InsetMathHull(buf, hullMultline)));
                                parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name));
                        }
 
@@ -1534,17 +1550,18 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        error("bad math environment");
                                        break;
                                }
-                               cell->push_back(MathAtom(new InsetMathHull(hullGather)));
+                               cell->push_back(MathAtom(new InsetMathHull(buf, hullGather)));
                                parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name));
                        }
 
                        else if (latexkeys const * l = in_word_set(name)) {
                                if (l->inset == "matrix") {
-                                       cell->push_back(createInsetMath(name));
+                                       cell->push_back(createInsetMath(name, buf));
                                        parse2(cell->back(), FLAG_END, mode, false);
                                } else if (l->inset == "split") {
                                        docstring const valign = parse_verbatim_option() + 'c';
-                                       cell->push_back(MathAtom(new InsetMathSplit(name, (char)valign[0])));
+                                       cell->push_back(MathAtom(
+                                               new InsetMathSplit(buf, name, (char)valign[0])));
                                        parse2(cell->back(), FLAG_END, mode, false);
                                } else {
                                        success_ = false;
@@ -1557,7 +1574,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                                       << "'." << endl;
                                        }
                                        // create generic environment inset
-                                       cell->push_back(MathAtom(new InsetMathEnv(name)));
+                                       cell->push_back(MathAtom(new InsetMathEnv(buf, name)));
                                        parse(cell->back().nucleus()->cell(0), FLAG_END, mode);
                                }
                        }
@@ -1570,7 +1587,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                               << to_utf8(name) << "'" << endl;
                                }
                                // create generic environment inset
-                               cell->push_back(MathAtom(new InsetMathEnv(name)));
+                               cell->push_back(MathAtom(new InsetMathEnv(buf, name)));
                                parse(cell->back().nucleus()->cell(0), FLAG_END, mode);
                        }
                }
@@ -1606,7 +1623,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        if (grid.asHullInset()) {
                                grid.asHullInset()->label(cellrow, label);
                        } else {
-                               cell->push_back(createInsetMath(t.cs()));
+                               cell->push_back(createInsetMath(t.cs(), buf));
                                cell->push_back(MathAtom(new InsetMathBrace(ar)));
                        }
                }
@@ -1614,7 +1631,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                else if (t.cs() == "choose" || t.cs() == "over"
                                || t.cs() == "atop" || t.cs() == "brace"
                                || t.cs() == "brack") {
-                       MathAtom at = createInsetMath(t.cs());
+                       MathAtom at = createInsetMath(t.cs(), buf);
                        at.nucleus()->cell(0) = *cell;
                        cell->clear();
                        parse(at.nucleus()->cell(1), flags, mode);
@@ -1624,25 +1641,25 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
 
                else if (t.cs() == "color") {
                        docstring const color = parse_verbatim_item();
-                       cell->push_back(MathAtom(new InsetMathColor(true, color)));
+                       cell->push_back(MathAtom(new InsetMathColor(buf, true, color)));
                        parse(cell->back().nucleus()->cell(0), flags, mode);
                        return success_;
                }
 
                else if (t.cs() == "textcolor") {
                        docstring const color = parse_verbatim_item();
-                       cell->push_back(MathAtom(new InsetMathColor(false, color)));
+                       cell->push_back(MathAtom(new InsetMathColor(buf, false, color)));
                        parse(cell->back().nucleus()->cell(0), FLAG_ITEM, InsetMath::TEXT_MODE);
                }
 
                else if (t.cs() == "normalcolor") {
-                       cell->push_back(createInsetMath(t.cs()));
+                       cell->push_back(createInsetMath(t.cs(), buf));
                        parse(cell->back().nucleus()->cell(0), flags, mode);
                        return success_;
                }
 
                else if (t.cs() == "substack") {
-                       cell->push_back(createInsetMath(t.cs()));
+                       cell->push_back(createInsetMath(t.cs(), buf));
                        parse2(cell->back(), FLAG_ITEM, mode, false);
                }
 
@@ -1650,12 +1667,12 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        odocstringstream os;
                        while (good() && nextToken().cat() != catBegin)
                                os << getToken().asInput();
-                       cell->push_back(createInsetMath(t.cs() + os.str()));
+                       cell->push_back(createInsetMath(t.cs() + os.str(), buf));
                        parse2(cell->back(), FLAG_ITEM, mode, false);
                }
 
                else if (t.cs() == "framebox" || t.cs() == "makebox") {
-                       cell->push_back(createInsetMath(t.cs()));
+                       cell->push_back(createInsetMath(t.cs(), buf));
                        parse(cell->back().nucleus()->cell(0), FLAG_OPTION, InsetMath::TEXT_MODE);
                        parse(cell->back().nucleus()->cell(1), FLAG_OPTION, InsetMath::TEXT_MODE);
                        parse(cell->back().nucleus()->cell(2), FLAG_ITEM, InsetMath::TEXT_MODE);
@@ -1664,9 +1681,9 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                else if (t.cs() == "tag") {
                        if (nextToken().character() == '*') {
                                getToken();
-                               cell->push_back(createInsetMath(t.cs() + '*'));
+                               cell->push_back(createInsetMath(t.cs() + '*', buf));
                        } else
-                               cell->push_back(createInsetMath(t.cs()));
+                               cell->push_back(createInsetMath(t.cs(), buf));
                        parse(cell->back().nucleus()->cell(0), FLAG_ITEM, InsetMath::TEXT_MODE);
                }
 
@@ -1679,9 +1696,9 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        else {
                                // Since the Length class cannot use length variables
                                // we must not create an InsetMathSpace.
-                               cell->push_back(MathAtom(new MathMacro(name)));
+                               cell->push_back(MathAtom(new MathMacro(buf, name)));
                                MathData ar;
-                               mathed_parse_cell(ar, '{' + arg + '}');
+                               mathed_parse_cell(ar, '{' + arg + '}', mode_);
                                cell->append(ar);
                        }
                }
@@ -1690,7 +1707,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                else if (t.cs() == "infer") {
                        MathData ar;
                        parse(ar, FLAG_OPTION, mode);
-                       cell->push_back(createInsetMath(t.cs()));
+                       cell->push_back(createInsetMath(t.cs(), buf));
                        parse2(cell->back(), FLAG_ITEM, mode, false);
                }
 
@@ -1749,8 +1766,15 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                }
 
                else if (t.cs().size()) {
+                       bool const no_mhchem =
+                               (t.cs() == "ce" || t.cs() == "cf") && buf
+                               && buf->params().use_mhchem == BufferParams::package_off;
+                       bool const is_user_macro = no_mhchem ||
+                               (buf && (mode_ & Parse::TRACKMACRO
+                                       ? buf->usermacros.count(t.cs()) != 0
+                                       : buf->getMacro(t.cs(), false) != 0));
                        latexkeys const * l = in_word_set(t.cs());
-                       if (l) {
+                       if (l && !is_user_macro) {
                                if (l->inset == "big") {
                                        skipSpaces();
                                        docstring const delim = getToken().asInput();
@@ -1758,19 +1782,19 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                                cell->push_back(MathAtom(
                                                        new InsetMathBig(t.cs(), delim)));
                                        else {
-                                               cell->push_back(createInsetMath(t.cs()));
+                                               cell->push_back(createInsetMath(t.cs(), buf));
                                                putback();
                                        }
                                }
 
                                else if (l->inset == "font") {
-                                       cell->push_back(createInsetMath(t.cs()));
+                                       cell->push_back(createInsetMath(t.cs(), buf));
                                        parse(cell->back().nucleus()->cell(0),
                                                FLAG_ITEM, asMode(mode, l->extra));
                                }
 
                                else if (l->inset == "oldfont") {
-                                       cell->push_back(createInsetMath(t.cs()));
+                                       cell->push_back(createInsetMath(t.cs(), buf));
                                        parse(cell->back().nucleus()->cell(0),
                                                flags | FLAG_ALIGN, asMode(mode, l->extra));
                                        if (prevToken().cat() != catAlign &&
@@ -1780,7 +1804,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                }
 
                                else if (l->inset == "style") {
-                                       cell->push_back(createInsetMath(t.cs()));
+                                       cell->push_back(createInsetMath(t.cs(), buf));
                                        parse(cell->back().nucleus()->cell(0),
                                                flags | FLAG_ALIGN, mode);
                                        if (prevToken().cat() != catAlign &&
@@ -1790,7 +1814,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                }
 
                                else {
-                                       MathAtom at = createInsetMath(t.cs());
+                                       MathAtom at = createInsetMath(t.cs(), buf);
                                        for (InsetMath::idx_type i = 0; i < at->nargs(); ++i)
                                                parse(at.nucleus()->cell(i),
                                                        FLAG_ITEM, asMode(mode, l->extra));
@@ -1800,7 +1824,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
 
                        else {
                                bool is_unicode_symbol = false;
-                               if (mode == InsetMath::TEXT_MODE) {
+                               if (mode == InsetMath::TEXT_MODE && !is_user_macro) {
                                        int num_tokens = 0;
                                        docstring cmd = prevToken().asInput();
                                        CatCode cat = nextToken().cat();
@@ -1837,7 +1861,9 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                        }
                                }
                                if (!is_unicode_symbol) {
-                                       MathAtom at = createInsetMath(t.cs());
+                                       MathAtom at = is_user_macro ?
+                                               MathAtom(new MathMacro(buf, t.cs()))
+                                               : createInsetMath(t.cs(), buf);
                                        InsetMath::mode_type m = mode;
                                        //if (m == InsetMath::UNDECIDED_MODE)
                                        //lyxerr << "default creation: m1: " << m << endl;
@@ -1877,33 +1903,36 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
 
 bool mathed_parse_cell(MathData & ar, docstring const & str, Parse::flags f)
 {
-       return Parser(str, f).parse(ar, 0, f & Parse::TEXTMODE ?
+       return Parser(str, f, ar.buffer()).parse(ar, 0, f & Parse::TEXTMODE ?
                                InsetMath::TEXT_MODE : InsetMath::MATH_MODE);
 }
 
 
 bool mathed_parse_cell(MathData & ar, istream & is, Parse::flags f)
 {
-       return Parser(is, f).parse(ar, 0, f & Parse::TEXTMODE ?
+       return Parser(is, f, ar.buffer()).parse(ar, 0, f & Parse::TEXTMODE ?
                                InsetMath::TEXT_MODE : InsetMath::MATH_MODE);
 }
 
 
-bool mathed_parse_normal(MathAtom & t, docstring const & str, Parse::flags f)
+bool mathed_parse_normal(Buffer * buf, MathAtom & t, docstring const & str,
+                        Parse::flags f)
 {
-       return Parser(str, f).parse(t);
+       return Parser(str, f, buf).parse(t);
 }
 
 
-bool mathed_parse_normal(MathAtom & t, Lexer & lex, Parse::flags f)
+bool mathed_parse_normal(Buffer * buf, MathAtom & t, Lexer & lex,
+                        Parse::flags f)
 {
-       return Parser(lex, f).parse(t);
+       return Parser(lex, f, buf).parse(t);
 }
 
 
-bool mathed_parse_normal(InsetMathGrid & grid, docstring const & str, Parse::flags f)
+bool mathed_parse_normal(InsetMathGrid & grid, docstring const & str,
+                        Parse::flags f)
 {
-       return Parser(str, f).parse1(grid, 0, f & Parse::TEXTMODE ?
+       return Parser(str, f, &grid.buffer()).parse1(grid, 0, f & Parse::TEXTMODE ?
                        InsetMath::TEXT_MODE : InsetMath::MATH_MODE, false);
 }