X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2FMathParser.cpp;h=ca2eb0f6e5114ef46a33251d6dabd248505aade8;hb=71623b88b2c613dd4ab826a9783a53e840bcd6e1;hp=234bfd8728c0367f6eaee30840588703ff981112;hpb=5dc9568f8d7e1eea485658a9a6d2e0f12114ddaa;p=lyx.git diff --git a/src/mathed/MathParser.cpp b/src/mathed/MathParser.cpp index 234bfd8728..ca2eb0f6e5 100644 --- a/src/mathed/MathParser.cpp +++ b/src/mathed/MathParser.cpp @@ -64,6 +64,7 @@ following hack as starting point to write some macros: #include "InsetMathString.h" #include "InsetMathTabular.h" #include "MathMacroTemplate.h" +#include "MathExtern.h" #include "MathFactory.h" #include "MathMacroArgument.h" #include "MathSupport.h" @@ -73,9 +74,10 @@ following hack as starting point to write some macros: #include "Encoding.h" #include "Lexer.h" -#include "support/debug.h" #include "support/convert.h" +#include "support/debug.h" #include "support/docstream.h" +#include "support/unique_ptr.h" #include @@ -228,6 +230,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. + * Do never delete a row that contains a multicolumn, even if all cells empty, + * since the multicolumn information would get lost otherwise. * 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. */ @@ -235,7 +239,9 @@ void delEmptyLastRow(InsetMathGrid & grid) { InsetMathGrid::row_type const row = grid.nrows() - 1; for (InsetMathGrid::col_type col = 0; col < grid.ncols(); ++col) { - if (!grid.cell(grid.index(row, col)).empty()) + InsetMathGrid::idx_type const idx = grid.index(row, col); + if (!grid.cell(idx).empty() || + grid.cellinfo(idx).multi_ != InsetMathGrid::CELL_NORMAL) return; } // Copy the row information of the empty row (which would contain the @@ -395,11 +401,15 @@ public: bool parse1(InsetMathGrid & grid, unsigned flags, mode_type mode, bool numbered); /// - MathData parse(unsigned flags, mode_type mode); - /// int lineno() const { return lineno_; } /// void putback(); + /// store current position + void pushPosition(); + /// restore previous position + void popPosition(); + /// forget last saved position + void dropPosition(); private: /// @@ -423,8 +433,6 @@ private: /// void push_back(Token const & t); /// - void pop_back(); - /// Token const & prevToken() const; /// Token const & nextToken() const; @@ -447,6 +455,8 @@ private: vector tokens_; /// unsigned pos_; + /// + std::vector positions_; /// Stack of active environments vector environments_; /// @@ -487,12 +497,6 @@ void Parser::push_back(Token const & t) } -void Parser::pop_back() -{ - tokens_.pop_back(); -} - - Token const & Parser::prevToken() const { static const Token dummy; @@ -528,6 +532,25 @@ void Parser::putback() } +void Parser::pushPosition() +{ + positions_.push_back(pos_); +} + + +void Parser::popPosition() +{ + pos_ = positions_.back(); + positions_.pop_back(); +} + + +void Parser::dropPosition() +{ + positions_.pop_back(); +} + + bool Parser::good() const { return pos_ < tokens_.size(); @@ -753,14 +776,6 @@ docstring Parser::parse_verbatim_item() } -MathData Parser::parse(unsigned flags, mode_type mode) -{ - MathData ar(buffer_); - parse(ar, flags, mode); - return ar; -} - - bool Parser::parse(MathData & array, unsigned flags, mode_type mode) { InsetMathGrid grid(buffer_, 1, 1); @@ -914,8 +929,13 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } else if (t.cat() == catParameter) { - Token const & n = getToken(); - cell->push_back(MathAtom(new MathMacroArgument(n.character()-'0'))); + Token const & n = nextToken(); + char_type c = n.character(); + if (c && '0' < c && c <= '9') { + cell->push_back(MathAtom(new MathMacroArgument(c - '0'))); + getToken(); + } else + cell->push_back(MathAtom(new InsetMathHash())); } else if (t.cat() == catActive) @@ -1039,10 +1059,10 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, t.cs() == "def") { if (t.cs() == "global") getToken(); - + // get name docstring name = getToken().cs(); - + // read parameters int nargs = 0; docstring pars; @@ -1051,17 +1071,17 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, ++nargs; } nargs /= 2; - + // read definition MathData def; parse(def, FLAG_ITEM, InsetMath::UNDECIDED_MODE); - + // is a version for display attached? skipSpaces(); MathData display; if (nextToken().cat() == catBegin) parse(display, FLAG_ITEM, InsetMath::MATH_MODE); - + cell->push_back(MathAtom(new MathMacroTemplate(buf, name, nargs, 0, MacroTypeDef, vector(), def, display))); @@ -1069,7 +1089,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, if (buf && (mode_ & Parse::TRACKMACRO)) buf->usermacros.insert(name); } - + else if (t.cs() == "newcommand" || t.cs() == "renewcommand" || t.cs() == "newlyxcommand") { @@ -1083,13 +1103,13 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, error("'}' in \\newcommand expected"); return success_; } - + // get arity docstring const arg = getArg('[', ']'); int nargs = 0; if (!arg.empty()) nargs = convert(arg); - + // optional argument given? skipSpaces(); int optionals = 0; @@ -1100,16 +1120,16 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, parse(optionalValues[optionals], FLAG_BRACK_LAST, mode); ++optionals; } - + MathData def; parse(def, FLAG_ITEM, InsetMath::UNDECIDED_MODE); - + // is a version for display attached? skipSpaces(); MathData display; if (nextToken().cat() == catBegin) parse(display, FLAG_ITEM, InsetMath::MATH_MODE); - + cell->push_back(MathAtom(new MathMacroTemplate(buf, name, nargs, optionals, MacroTypeNewcommand, optionalValues, def, display))); @@ -1117,7 +1137,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, if (buf && (mode_ & Parse::TRACKMACRO)) buf->usermacros.insert(name); } - + else if (t.cs() == "newcommandx" || t.cs() == "renewcommandx") { // \newcommandx{\foo}[2][usedefault, addprefix=\global,1=default]{#1,#2} @@ -1132,7 +1152,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } } else name = getToken().cs(); - + // get arity docstring const arg = getArg('[', ']'); if (arg.empty()) { @@ -1140,14 +1160,14 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, return success_; } int nargs = convert(arg); - + // get options int optionals = 0; vector optionalValues; if (nextToken().character() == '[') { // skip '[' getToken(); - + // handle 'opt=value' options, separated by ','. skipSpaces(); while (nextToken().character() != ']' && good()) { @@ -1160,14 +1180,14 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, "for given optional parameter."); return success_; } - + // skip '=' if (getToken().character() != '=') { error("'=' and optional parameter value " "expected for \\newcommandx"); return success_; } - + // get value int optNum = max(size_t(n), optionalValues.size()); optionalValues.resize(optNum); @@ -1182,12 +1202,12 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } else if (nextToken().cat() == catLetter) { // we in fact ignore every non-optional // parameter - + // get option name docstring opt; while (nextToken().cat() == catLetter) opt += getChar(); - + // value? skipSpaces(); MathData value; @@ -1195,14 +1215,14 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, getToken(); while (nextToken().character() != ']' && nextToken().character() != ',') - parse(value, FLAG_ITEM, + parse(value, FLAG_ITEM, InsetMath::UNDECIDED_MODE); } } else { error("option for \\newcommandx expected"); return success_; } - + // skip komma skipSpaces(); if (nextToken().character() == ',') { @@ -1214,7 +1234,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, return success_; } } - + // skip ']' if (!good()) return success_; @@ -1307,14 +1327,36 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, else if (t.cs() == "\\") { if (flags & FLAG_ALIGN) return success_; - bool added = false; + bool starred = false; + docstring arg; if (nextToken().asInput() == "*") { getToken(); - added = addRow(grid, cellrow, docstring(), false); - } else if (good()) - added = addRow(grid, cellrow, getArg('[', ']')); - else + starred = true; + } else if (nextToken().asInput() == "[") + arg = getArg('[', ']'); + else if (!good()) error("missing token after \\\\"); + // skip "{}" added in front of "[" (the + // counterpart is in InsetMathGrid::eolString()) + // skip spaces because formula could come from tex2lyx + bool skipBraces = false; + pushPosition(); + if (nextToken().cat() == catBegin) { + getToken(); + if (nextToken().cat() == catEnd) { + getToken(); + pushPosition(); + skipSpaces(); + if (nextToken().asInput() == "[") + skipBraces = true; + popPosition(); + } + } + if (skipBraces) + dropPosition(); + else + popPosition(); + bool const added = addRow(grid, cellrow, arg, !starred); if (added) { cellcol = 0; if (grid.asHullInset()) @@ -1325,38 +1367,42 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } } -#if 0 - else if (t.cs() == "multicolumn") { - // extract column count and insert dummy cells + else if (t.cs() == "multicolumn" && grid.handlesMulticolumn()) { + // if the columns are specified numerically, + // extract column count and insert dummy cells, + // otherwise parse it as an user macro MathData count; parse(count, FLAG_ITEM, mode); - int cols = 1; - if (!extractNumber(count, cols)) { - success_ = false; - lyxerr << " can't extract number of cells from " << count << endl; - } - // resize the table if necessary - for (int i = 0; i < cols; ++i) { - if (addCol(grid, cellcol)) { - cell = &grid.cell(grid.index( - cellrow, cellcol)); - // mark this as dummy - grid.cellinfo(grid.index( - cellrow, cellcol)).dummy_ = true; + int cols; + if (extractNumber(count, cols)) { + // resize the table if necessary + size_t first = grid.index(cellrow, cellcol); + for (int i = 1; i < cols; ++i) { + if (addCol(grid, cellcol)) { + size_t const idx = grid.index(cellrow, cellcol); + grid.cellinfo(idx).multi_ = + InsetMathGrid::CELL_PART_OF_MULTICOLUMN; + } } - } - // the last cell is the real thing, not a dummy - grid.cellinfo(grid.index(cellrow, cellcol)).dummy_ = false; - // read special alignment - MathData align; - parse(align, FLAG_ITEM, mode); - //grid.cellinfo(grid.index(cellrow, cellcol)).align_ = extractString(align); + // the first cell is the real thing, not a dummy + cell = &grid.cell(first); + grid.cellinfo(first).multi_ = + InsetMathGrid::CELL_BEGIN_OF_MULTICOLUMN; + + // read special alignment + MathData align; + parse(align, FLAG_ITEM, mode); + grid.cellinfo(first).align_ = asString(align); - // parse the remaining contents into the "real" cell - parse(*cell, FLAG_ITEM, mode); + // parse the remaining contents into the "real" cell + parse(*cell, FLAG_ITEM, mode); + } else { + MathAtom at = MathAtom(new MathMacro(buf, t.cs())); + cell->push_back(at); + cell->push_back(MathAtom(new InsetMathBrace(count))); + } } -#endif else if (t.cs() == "limits" || t.cs() == "nolimits") { CatCode const cat = nextToken().cat(); @@ -1368,15 +1414,13 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } } - else if (t.cs() == "nonumber") { - if (grid.asHullInset()) - grid.asHullInset()->numbered(cellrow, false); - } + // \notag is the same as \nonumber if amsmath is used + else if ((t.cs() == "nonumber" || t.cs() == "notag") && + grid.asHullInset()) + grid.asHullInset()->numbered(cellrow, false); - else if (t.cs() == "number") { - if (grid.asHullInset()) - grid.asHullInset()->numbered(cellrow, true); - } + else if (t.cs() == "number" && grid.asHullInset()) + grid.asHullInset()->numbered(cellrow, true); else if (t.cs() == "hline") { grid.rowinfo(cellrow).lines_ ++; @@ -1434,7 +1478,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, else if (t.cs() == "cfrac") { // allowed formats are \cfrac[pos]{num}{denom} docstring const arg = getArg('[', ']'); - //lyxerr << "got so far: '" << arg << "'" << endl; + //lyxerr << "got so far: '" << arg << "'" << endl; if (arg == "l") cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRACLEFT))); else if (arg == "r") @@ -1494,6 +1538,18 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode); } + else if (t.cs() == "xhookrightarrow" || t.cs() == "xhookleftarrow" || + t.cs() == "xRightarrow" || t.cs() == "xLeftarrow" || + t.cs() == "xleftrightarrow" || t.cs() == "xLeftrightarrow" || + t.cs() == "xrightharpoondown" || t.cs() == "xrightharpoonup" || + t.cs() == "xleftharpoondown" || t.cs() == "xleftharpoonup" || + t.cs() == "xleftrightharpoons" || t.cs() == "xrightleftharpoons" || + t.cs() == "xmapsto") { + 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(buf, t.cs()))); @@ -1534,13 +1590,13 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, else if (t.cs() == "begin") { docstring const name = getArg('{', '}'); - + if (name.empty()) { success_ = false; error("found invalid environment"); return success_; } - + environments_.push_back(name); if (name == "array" || name == "subarray") { @@ -1689,7 +1745,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, lyxerr << "found math environment `" << to_utf8(name) << "' in symbols file with unsupported inset `" - << to_utf8(l->inset) + << l->inset << "'." << endl; } // create generic environment inset @@ -1711,7 +1767,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } } - else if (t.cs() == "kern") { + else if (t.cs() == "kern" || t.cs() == "mkern") { // FIXME: A hack... docstring s; int num_tokens = 0; @@ -1729,7 +1785,7 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, break; } if (s.empty()) - cell->push_back(MathAtom(new InsetMathKern)); + cell->push_back(MathAtom(new MathMacro(buf, t.cs()))); else cell->push_back(MathAtom(new InsetMathKern(s))); } @@ -1879,23 +1935,6 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, cell->push_back(createInsetMath(t.cs(), buf)); parse2(cell->back(), FLAG_ITEM, mode, false); } - - // Disabled - else if (1 && t.cs() == "ar") { - auto_ptr p(new InsetMathXYArrow); - // try to read target - parse(p->cell(0), FLAG_OTPTION, mode); - // try to read label - if (nextToken().cat() == catSuper || nextToken().cat() == catSub) { - p->up_ = nextToken().cat() == catSuper; - getToken(); - parse(p->cell(1), FLAG_ITEM, mode); - //lyxerr << "read label: " << p->cell(1) << endl; - } - - cell->push_back(MathAtom(p.release())); - //lyxerr << "read cell: " << cell << endl; - } #endif else if (t.cs() == "lyxmathsym") { @@ -2074,7 +2113,8 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, //} for (InsetMath::idx_type i = start; i < at->nargs(); ++i) { parse(at.nucleus()->cell(i), FLAG_ITEM, m); - skipSpaces(); + if (mode == InsetMath::MATH_MODE) + skipSpaces(); } cell->push_back(at); } @@ -2095,6 +2135,15 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned flags, } // anonymous namespace +// FIXME This will likely need some work. +char const * latexkeys::MathMLtype() const +{ + if (extra == "mathord") + return "mi"; + return "mo"; +} + + bool mathed_parse_cell(MathData & ar, docstring const & str, Parse::flags f) { return Parser(str, f, ar.buffer()).parse(ar, 0, f & Parse::TEXTMODE ?