]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/MathParser.cpp
Years forgotten files.
[lyx.git] / src / mathed / MathParser.cpp
index f80dba73038976e13fe867bad093168c4833c35e..05ceed80f251bf6d78f210276f8a03e8cf8b1b01 100644 (file)
@@ -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,11 @@ 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"
@@ -214,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|}
@@ -225,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)
 {
@@ -241,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
@@ -318,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:
        ///
@@ -334,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().
@@ -520,7 +538,6 @@ char_type Parser::getChar()
 {
        if (!good()) {
                error("The input stream is not well...");
-               putback();
                return 0;
        }
        return tokens_[pos_++].character();
@@ -529,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)
@@ -614,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
@@ -832,9 +854,16 @@ 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(buf, hullEquation)));
-                                       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();
@@ -855,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);
+                               }
                        }
                }
 
@@ -879,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;
@@ -913,7 +953,7 @@ 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())
+                       if (cell->empty())
                                cell->push_back(MathAtom(new InsetMathScript(buf, up)));
                        else if (cell->back()->asScriptInset() &&
                                        !cell->back()->asScriptInset()->has(up))
@@ -980,7 +1020,7 @@ 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(buf, s)));
                        skipSpaces();
@@ -991,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);
                }
 
@@ -1200,12 +1240,8 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                }
 
                else if (t.cs() == "(") {
-                       if (mode == InsetMath::MATH_MODE) {
-                               error("bad math environment");
-                               break;
-                       }
-                       cell->push_back(MathAtom(new InsetMathHull(buf, hullSimple)));
-                       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() == "[") {
@@ -1242,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_;
                                }
@@ -1316,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())
@@ -1339,7 +1379,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                else if (t.cs() == "sqrt") {
                        MathData ar;
                        parse(ar, FLAG_OPTION, mode);
-                       if (ar.size()) {
+                       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);
@@ -1349,11 +1389,19 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        }
                }
 
+               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()) {
+                       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);
@@ -1367,7 +1415,7 @@ 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()) {
+                       if (!ar.empty()) {
                                cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::UNITFRAC, 3)));
                                cell->back().nucleus()->cell(2) = ar;
                        } else {
@@ -1395,6 +1443,45 @@ 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(), buf));
                        parse(cell->back().nucleus()->cell(1), FLAG_OPTION, mode);
@@ -1473,12 +1560,8 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        }
 
                        else if (name == "math") {
-                               if (mode == InsetMath::MATH_MODE) {
-                                       error("bad math environment");
-                                       break;
-                               }
-                               cell->push_back(MathAtom(new InsetMathHull(buf, hullSimple)));
-                               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*"
@@ -1676,6 +1759,11 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                else if (t.cs() == "substack") {
                        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") {
@@ -1684,6 +1772,19 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                                os << getToken().asInput();
                        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") {
@@ -1702,12 +1803,17 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
                        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.
@@ -1765,29 +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()) {
+               else if (!t.cs().empty()) {
                        bool const no_mhchem =
-                               (t.cs() == "ce" || t.cs() == "cf") && buf
-                               && buf->params().use_mhchem == BufferParams::package_off;
+                               (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));
+                                        ? 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") {
@@ -1856,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 += '{';
@@ -1865,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 {
@@ -1889,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;
                                        //}