X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2FMathParser.cpp;h=05ceed80f251bf6d78f210276f8a03e8cf8b1b01;hb=f6d505c1ee494ab0d30eebba86082c86a915e1df;hp=74db5acc92461b04fa0cb90275ccb65ceab136a7;hpb=a1a34443eff8d3224141a8d170cef3d628fb1ae4;p=lyx.git diff --git a/src/mathed/MathParser.cpp b/src/mathed/MathParser.cpp index 74db5acc92..05ceed80f2 100644 --- a/src/mathed/MathParser.cpp +++ b/src/mathed/MathParser.cpp @@ -42,6 +42,7 @@ following hack as starting point to write some macros: #include "InsetMathArray.h" #include "InsetMathBig.h" #include "InsetMathBrace.h" +#include "InsetMathCancelto.h" #include "InsetMathChar.h" #include "InsetMathColor.h" #include "InsetMathComment.h" @@ -55,9 +56,12 @@ following hack as starting point to write some macros: #include "InsetMathRef.h" #include "InsetMathRoot.h" #include "InsetMathScript.h" +#include "InsetMathSideset.h" #include "InsetMathSpace.h" #include "InsetMathSplit.h" #include "InsetMathSqrt.h" +#include "InsetMathStackrel.h" +#include "InsetMathString.h" #include "InsetMathTabular.h" #include "MathMacroTemplate.h" #include "MathFactory.h" @@ -65,6 +69,7 @@ following hack as starting point to write some macros: #include "MathSupport.h" #include "Buffer.h" +#include "BufferParams.h" #include "Encoding.h" #include "Lexer.h" @@ -212,7 +217,7 @@ bool addCol(InsetMathGrid & grid, InsetMathGrid::col_type & cellcol) /*! - * Check wether the last row is empty and remove it if yes. + * Check whether the last row is empty and remove it if yes. * Otherwise the following code * \verbatim \begin{array}{|c|c|} @@ -223,6 +228,8 @@ bool addCol(InsetMathGrid & grid, InsetMathGrid::col_type & cellcol) * \endverbatim * will result in a grid with 3 rows (+ the dummy row that is always present), * because the last '\\' opens a new row. + * Note that this is only needed for inner-hull grid types, such as array + * or aligned, but not for outer-hull grid types, such as eqnarray or align. */ void delEmptyLastRow(InsetMathGrid & grid) { @@ -239,6 +246,19 @@ void delEmptyLastRow(InsetMathGrid & grid) } +/*! + * Tell whether the environment name corresponds to an inner-hull grid type. + */ +bool innerHull(docstring const & name) +{ + // For [bB]matrix, [vV]matrix, and pmatrix we can check the suffix only + return name == "array" || name == "cases" || name == "aligned" + || name == "alignedat" || name == "gathered" || name == "split" + || name == "subarray" || name == "tabular" || name == "matrix" + || name == "smallmatrix" || name.substr(1) == "matrix"; +} + + // These are TeX's catcodes enum CatCode { catEscape, // 0 backslash @@ -316,9 +336,9 @@ public: /// char_type character() const { return char_; } /// - docstring asString() const { return cs_.size() ? cs_ : docstring(1, char_); } + docstring asString() const { return !cs_.empty() ? cs_ : docstring(1, char_); } /// - docstring asInput() const { return cs_.size() ? '\\' + cs_ : docstring(1, char_); } + docstring asInput() const { return !cs_.empty() ? '\\' + cs_ : docstring(1, char_); } private: /// @@ -332,7 +352,7 @@ private: ostream & operator<<(ostream & os, Token const & t) { - if (t.cs().size()) { + if (!t.cs().empty()) { docstring const & cs = t.cs(); // FIXME: For some strange reason, the stream operator instanciate // a new Token before outputting the contents of t.cs(). @@ -442,8 +462,6 @@ Parser::Parser(Lexer & lexer, parse_mode mode, Buffer * buf) : lineno_(lexer.lineNumber()), pos_(0), mode_(mode), success_(true), buffer_(buf) { - if (buf) - buf->updateMacros(); tokenize(lexer.getStream()); lexer.eatLine(); } @@ -452,8 +470,6 @@ Parser::Parser(Lexer & lexer, parse_mode mode, Buffer * buf) Parser::Parser(istream & is, parse_mode mode, Buffer * buf) : lineno_(0), pos_(0), mode_(mode), success_(true), buffer_(buf) { - if (buf) - buf->updateMacros(); tokenize(is); } @@ -461,8 +477,6 @@ Parser::Parser(istream & is, parse_mode mode, Buffer * buf) Parser::Parser(docstring const & str, parse_mode mode, Buffer * buf) : lineno_(0), pos_(0), mode_(mode), success_(true), buffer_(buf) { - if (buf) - buf->updateMacros(); tokenize(str); } @@ -524,7 +538,6 @@ char_type Parser::getChar() { if (!good()) { error("The input stream is not well..."); - putback(); return 0; } return tokens_[pos_++].character(); @@ -533,9 +546,12 @@ char_type Parser::getChar() docstring Parser::getArg(char_type left, char_type right) { + docstring result; skipSpaces(); - docstring result; + if (!good()) + return result; + char_type c = getChar(); if (c != left) @@ -618,6 +634,8 @@ void Parser::tokenize(docstring const & buffer) if (!is) { error("unexpected end of input"); } else { + if (c == '\n') + c = ' '; docstring s(1, c); if (catcode(c) == catLetter) { // collect letters @@ -681,12 +699,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 @@ -737,7 +755,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; } @@ -745,7 +763,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_; @@ -766,6 +784,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); @@ -835,18 +854,25 @@ 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, buffer_))); - parse2(cell->back(), FLAG_SIMPLE, InsetMath::MATH_MODE, false); - getToken(); // skip the second '$' token + if (mode == InsetMath::UNDECIDED_MODE) { + cell->push_back(MathAtom(new InsetMathHull(buf, hullEquation))); + parse2(cell->back(), FLAG_SIMPLE, InsetMath::MATH_MODE, false); + getToken(); // skip the second '$' token + } else { + // This is not an outer hull and display math is + // not allowed inside text mode environments. + error("bad math environment"); + break; + } } else { // simple $...$ stuff putback(); if (mode == InsetMath::UNDECIDED_MODE) { - cell->push_back(MathAtom(new InsetMathHull(hullSimple, buffer_))); + 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); } } @@ -858,8 +884,19 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } else { - error("something strange in the parser"); - break; + Token const & n = getToken(); + if (n.cat() == catMath) { + error("something strange in the parser"); + break; + } else { + // This is inline math ($...$), but the parser thinks we are + // already in math mode and latex would issue an error, unless we + // are inside a text mode user macro. We have no way to tell, so + // let's play safe by using \ensuremath, as it will work in any case. + putback(); + cell->push_back(MathAtom(new InsetMathEnsureMath(buf))); + parse(cell->back().nucleus()->cell(0), FLAG_SIMPLE, InsetMath::MATH_MODE); + } } } @@ -882,7 +919,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } else if (t.cat() == catActive) - cell->push_back(MathAtom(new InsetMathChar(t.character()))); + cell->push_back(MathAtom(new InsetMathSpace(string(1, t.character()), ""))); else if (t.cat() == catBegin) { MathData ar; @@ -916,15 +953,15 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, bool up = (t.cat() == catSuper); // 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))); + if (cell->empty()) + 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 @@ -938,6 +975,14 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, // in an unreliable way. See this thread // http://www.mail-archive.com/lyx-devel%40lists.lyx.org/msg104917.html // for more details. + // However, we remove empty braces because they look + // ugly on screen and we are sure that they were added + // by the write() method (and will be re-added on save). + if (p->nuc().size() == 1 && + p->nuc().back()->asBraceInset() && + p->nuc().back()->asBraceInset()->cell(0).empty()) + p->nuc().erase(0); + parse(p->cell(p->idxOfScript(up)), FLAG_ITEM, mode); if (limits) { p->limits(limits); @@ -958,7 +1003,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())) { @@ -975,9 +1020,9 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, Token const & t = getToken(); if (t.cat() == catNewline) break; - s += t.asString(); + s += t.asInput(); } - cell->push_back(MathAtom(new InsetMathComment(s))); + cell->push_back(MathAtom(new InsetMathComment(buf, s))); skipSpaces(); } @@ -986,7 +1031,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, // else if (t.cs() == "lyxlock") { - if (cell->size()) + if (!cell->empty()) cell->back().nucleus()->lock(true); } @@ -1017,9 +1062,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, buffer_, + cell->push_back(MathAtom(new MathMacroTemplate(buf, + name, nargs, 0, MacroTypeDef, vector(), def, display))); + + if (buf && (mode_ & Parse::TRACKMACRO)) + buf->usermacros.insert(name); } else if (t.cs() == "newcommand" || @@ -1062,9 +1110,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, buffer_, + 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" || @@ -1180,18 +1231,17 @@ 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, buffer_, + 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() == "(") { - if (mode == InsetMath::MATH_MODE) { - error("bad math environment"); - break; - } - cell->push_back(MathAtom(new InsetMathHull(hullSimple, buffer_))); - parse2(cell->back(), FLAG_SIMPLE2, InsetMath::MATH_MODE, false); + cell->push_back(MathAtom(new InsetMathEnsureMath(buf))); + parse(cell->back().nucleus()->cell(0), FLAG_SIMPLE2, InsetMath::MATH_MODE); } else if (t.cs() == "[") { @@ -1199,7 +1249,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, error("bad math environment"); break; } - cell->push_back(MathAtom(new InsetMathHull(hullEquation, buffer_))); + cell->push_back(MathAtom(new InsetMathHull(buf, hullEquation))); parse2(cell->back(), FLAG_EQUATION, InsetMath::MATH_MODE, false); } @@ -1228,7 +1278,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, // probably need to refine this test. // Right now we only have to test for // single line hull insets. - if (grid.nrows() > 1) + if (grid.nrows() > 1 && innerHull(name)) delEmptyLastRow(grid); return success_; } @@ -1302,11 +1352,15 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } #endif - else if (t.cs() == "limits") - limits = 1; - - else if (t.cs() == "nolimits") - limits = -1; + else if (t.cs() == "limits" || t.cs() == "nolimits") { + CatCode const cat = nextToken().cat(); + if (cat == catSuper || cat == catSub) + limits = t.cs() == "limits" ? 1 : -1; + else { + MathAtom at = createInsetMath(t.cs(), buf); + cell->push_back(at); + } + } else if (t.cs() == "nonumber") { if (grid.asHullInset()) @@ -1325,26 +1379,34 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, else if (t.cs() == "sqrt") { MathData ar; parse(ar, FLAG_OPTION, mode); - if (ar.size()) { - cell->push_back(MathAtom(new InsetMathRoot)); + if (!ar.empty()) { + 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); } } + else if (t.cs() == "cancelto") { + MathData ar; + parse(ar, FLAG_ITEM, mode); + cell->push_back(MathAtom(new InsetMathCancelto(buf))); + cell->back().nucleus()->cell(1) = ar; + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); + } + else if (t.cs() == "unit") { // Allowed formats \unit[val]{unit} MathData ar; parse(ar, FLAG_OPTION, mode); - if (ar.size()) { - cell->push_back(MathAtom(new InsetMathFrac(InsetMathFrac::UNIT))); + if (!ar.empty()) { + 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); } } @@ -1353,11 +1415,11 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, // Here allowed formats are \unitfrac[val]{num}{denom} MathData ar; parse(ar, FLAG_OPTION, mode); - if (ar.size()) { - cell->push_back(MathAtom(new InsetMathFrac(InsetMathFrac::UNITFRAC, 3))); + if (!ar.empty()) { + 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); @@ -1368,11 +1430,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; @@ -1381,17 +1443,62 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, parse(cell->back().nucleus()->cell(1), FLAG_ITEM, mode); } + else if (t.cs() == "sideset") { + // Here allowed formats are \sideset{_{bl}^{tl}}{_{br}^{tr}}{operator} + MathData ar[2]; + InsetMathScript * script[2] = {0, 0}; + for (int i = 0; i < 2; ++i) { + parse(ar[i], FLAG_ITEM, mode); + if (ar[i].size() == 1) + script[i] = ar[i][0].nucleus()->asScriptInset(); + } + bool const hasscript[2] = {script[0] ? true : false, script[1] ? true : false}; + cell->push_back(MathAtom(new InsetMathSideset(buf, hasscript[0], hasscript[1]))); + if (hasscript[0]) { + if (script[0]->hasDown()) + cell->back().nucleus()->cell(1) = script[0]->down(); + if (script[0]->hasUp()) + cell->back().nucleus()->cell(2) = script[0]->up(); + } else + cell->back().nucleus()->cell(1) = ar[0]; + if (hasscript[1]) { + if (script[1]->hasDown()) + cell->back().nucleus()->cell(2 + hasscript[0]) = script[1]->down(); + if (script[1]->hasUp()) + cell->back().nucleus()->cell(3 + hasscript[0]) = script[1]->up(); + } else + cell->back().nucleus()->cell(2 + hasscript[0]) = ar[1]; + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); + } + + else if (t.cs() == "stackrel") { + // Here allowed formats are \stackrel[subscript]{superscript}{operator} + MathData ar; + parse(ar, FLAG_OPTION, mode); + cell->push_back(MathAtom(new InsetMathStackrel(buf, !ar.empty()))); + if (!ar.empty()) + cell->back().nucleus()->cell(2) = ar; + parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); + parse(cell->back().nucleus()->cell(1), FLAG_ITEM, mode); + } + 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()))); - parse(cell->back().nucleus()->cell(1), FLAG_OPTION, mode); - parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); + cell->push_back(MathAtom(new InsetMathRef(buf, t.cs()))); + docstring const opt = parse_verbatim_option(); + docstring const ref = parse_verbatim_item(); + if (!opt.empty()) { + cell->back().nucleus()->cell(1).push_back( + MathAtom(new InsetMathString(opt))); + } + cell->back().nucleus()->cell(0).push_back( + MathAtom(new InsetMathString(ref))); } else if (t.cs() == "left") { @@ -1408,7 +1515,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") { @@ -1426,7 +1533,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); } @@ -1434,13 +1541,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); } @@ -1448,17 +1555,13 @@ 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); } else if (name == "math") { - if (mode == InsetMath::MATH_MODE) { - error("bad math environment"); - break; - } - cell->push_back(MathAtom(new InsetMathHull(hullSimple, buffer_))); - parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, true); + cell->push_back(MathAtom(new InsetMathEnsureMath(buf))); + parse(cell->back().nucleus()->cell(0), FLAG_END, InsetMath::MATH_MODE); } else if (name == "equation" || name == "equation*" @@ -1467,7 +1570,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, error("bad math environment"); break; } - cell->push_back(MathAtom(new InsetMathHull(hullEquation, buffer_))); + cell->push_back(MathAtom(new InsetMathHull(buf, hullEquation))); parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, (name == "equation")); } @@ -1476,7 +1579,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, error("bad math environment"); break; } - cell->push_back(MathAtom(new InsetMathHull(hullEqnArray, buffer_))); + cell->push_back(MathAtom(new InsetMathHull(buf, hullEqnArray))); parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); } @@ -1485,7 +1588,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, error("bad math environment"); break; } - cell->push_back(MathAtom(new InsetMathHull(hullAlign, buffer_))); + cell->push_back(MathAtom(new InsetMathHull(buf, hullAlign))); parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); } @@ -1494,7 +1597,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, error("bad math environment"); break; } - cell->push_back(MathAtom(new InsetMathHull(hullFlAlign, buffer_))); + cell->push_back(MathAtom(new InsetMathHull(buf, hullFlAlign))); parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); } @@ -1505,7 +1608,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } // ignore this for a while getArg('{', '}'); - cell->push_back(MathAtom(new InsetMathHull(hullAlignAt, buffer_))); + cell->push_back(MathAtom(new InsetMathHull(buf, hullAlignAt))); parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); } @@ -1516,7 +1619,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } // ignore this for a while getArg('{', '}'); - cell->push_back(MathAtom(new InsetMathHull(hullXAlignAt, buffer_))); + cell->push_back(MathAtom(new InsetMathHull(buf, hullXAlignAt))); parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); } @@ -1527,7 +1630,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } // ignore this for a while getArg('{', '}'); - cell->push_back(MathAtom(new InsetMathHull(hullXXAlignAt, buffer_))); + cell->push_back(MathAtom(new InsetMathHull(buf, hullXXAlignAt))); parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); } @@ -1536,7 +1639,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, error("bad math environment"); break; } - cell->push_back(MathAtom(new InsetMathHull(hullMultline, buffer_))); + cell->push_back(MathAtom(new InsetMathHull(buf, hullMultline))); parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name)); } @@ -1545,17 +1648,18 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, error("bad math environment"); break; } - cell->push_back(MathAtom(new InsetMathHull(hullGather, buffer_))); + 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; @@ -1568,7 +1672,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); } } @@ -1581,7 +1685,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); } } @@ -1617,7 +1721,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))); } } @@ -1625,7 +1729,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); @@ -1635,38 +1739,56 @@ 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); + // Delete empty last row if present + InsetMathGrid & subgrid = + *(cell->back().nucleus()->asGridInset()); + if (subgrid.nrows() > 1) + delEmptyLastRow(subgrid); } else if (t.cs() == "xymatrix") { 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); + // Delete empty last row if present + InsetMathGrid & subgrid = + *(cell->back().nucleus()->asGridInset()); + if (subgrid.nrows() > 1) + delEmptyLastRow(subgrid); + } + + else if (t.cs() == "Diagram") { + odocstringstream os; + while (good() && nextToken().cat() != catBegin) + os << getToken().asInput(); + 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); @@ -1675,25 +1797,29 @@ 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); } - else if (t.cs() == "hspace" && nextToken().character() != '*') { + else if (t.cs() == "hspace") { + bool const prot = nextToken().character() == '*'; + if (prot) + getToken(); docstring const name = t.cs(); docstring const arg = parse_verbatim_item(); Length length; - if (isValidLength(to_utf8(arg), &length)) - cell->push_back(MathAtom(new InsetMathSpace(length))); + if (prot && arg == "\\fill") + cell->push_back(MathAtom(new InsetMathSpace("hspace*{\\fill}", ""))); + else if (isValidLength(to_utf8(arg), &length)) + cell->push_back(MathAtom(new InsetMathSpace(length, prot))); 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 + '}', - Parse::NORMAL, buffer_); + mathed_parse_cell(ar, '{' + arg + '}', mode_); cell->append(ar); } } @@ -1702,7 +1828,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); } @@ -1745,24 +1871,35 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, error("'}' expected in \\" + t.cs()); return success_; } + bool termination; docstring rem; do { - cmd = Encodings::fromLaTeXCommand(cmd, rem); + cmd = Encodings::fromLaTeXCommand(cmd, + Encodings::MATH_CMD | Encodings::TEXT_CMD, + termination, rem); for (size_t i = 0; i < cmd.size(); ++i) cell->push_back(MathAtom(new InsetMathChar(cmd[i]))); - if (rem.size()) { + if (!rem.empty()) { char_type c = rem[0]; cell->push_back(MathAtom(new InsetMathChar(c))); cmd = rem.substr(1); rem.clear(); } else cmd.clear(); - } while (cmd.size()); + } while (!cmd.empty()); } - else if (t.cs().size()) { - bool const is_user_macro = - buffer_ && buffer_->getMacro(t.cs(), false); + else if (!t.cs().empty()) { + bool const no_mhchem = + (t.cs() == "ce" || t.cs() == "cf") + && buf && buf->params().use_package("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 && !is_user_macro) { if (l->inset == "big") { @@ -1772,19 +1909,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 && @@ -1794,7 +1931,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 && @@ -1804,7 +1941,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)); @@ -1831,8 +1968,10 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } } bool is_combining; - char_type c = - Encodings::fromLaTeXCommand(cmd, is_combining); + bool termination; + char_type c = Encodings::fromLaTeXCommand(cmd, + Encodings::MATH_CMD | Encodings::TEXT_CMD, + is_combining, termination); if (is_combining) { if (cat == catLetter) cmd += '{'; @@ -1840,9 +1979,26 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, ++num_tokens; if (cat == catLetter) cmd += '}'; - c = Encodings::fromLaTeXCommand(cmd, is_combining); + c = Encodings::fromLaTeXCommand(cmd, + Encodings::MATH_CMD | Encodings::TEXT_CMD, + is_combining, termination); } if (c) { + if (termination) { + if (nextToken().cat() == catBegin) { + getToken(); + if (nextToken().cat() == catEnd) { + getToken(); + num_tokens += 2; + } else + putback(); + } else { + while (nextToken().cat() == catSpace) { + getToken(); + ++num_tokens; + } + } + } is_unicode_symbol = true; cell->push_back(MathAtom(new InsetMathChar(c))); } else { @@ -1852,8 +2008,8 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } if (!is_unicode_symbol) { MathAtom at = is_user_macro ? - MathAtom(new MathMacro(t.cs())) - : createInsetMath(t.cs()); + 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; @@ -1864,7 +2020,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, // this fails on \bigg[...\bigg] //MathData opt; //parse(opt, FLAG_OPTION, InsetMath::VERBATIM_MODE); - //if (opt.size()) { + //if (!opt.empty()) { // start = 1; // at.nucleus()->cell(0) = opt; //} @@ -1891,40 +2047,38 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } // anonymous namespace -bool mathed_parse_cell(MathData & ar, docstring const & str, - Parse::flags f, Buffer * buf) +bool mathed_parse_cell(MathData & ar, docstring const & str, Parse::flags f) { - return Parser(str, f, buf).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, Buffer * buf) +bool mathed_parse_cell(MathData & ar, istream & is, Parse::flags f) { - return Parser(is, f, buf).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, Buffer * buf) +bool mathed_parse_normal(Buffer * buf, MathAtom & t, docstring const & str, + Parse::flags f) { return Parser(str, f, buf).parse(t); } -bool mathed_parse_normal(MathAtom & t, Lexer & lex, - Parse::flags f, Buffer * buf) +bool mathed_parse_normal(Buffer * buf, MathAtom & t, Lexer & lex, + Parse::flags f) { return Parser(lex, f, buf).parse(t); } bool mathed_parse_normal(InsetMathGrid & grid, docstring const & str, - Parse::flags f, Buffer * buf) + Parse::flags f) { - return Parser(str, f, buf).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); }