#include "math_arrayinset.h"
#include "math_braceinset.h"
#include "math_charinset.h"
+#include "math_colorinset.h"
#include "math_commentinset.h"
#include "math_deliminset.h"
#include "math_envinset.h"
#include "lyxlex.h"
#include "debug.h"
-#include "support/lyxlib.h"
-#include <sstream>
+#include "support/convert.h"
-using lyx::support::atoi;
+#include <sstream>
using std::endl;
using std::fill;
}
+/*!
+ * Check wether the last row is empty and remove it if yes.
+ * Otherwise the following code
+ * \verbatim
+\begin{array}{|c|c|}
+\hline
+1 & 2 \\ \hline
+3 & 4 \\ \hline
+\end{array}
+ * \endverbatim
+ * will result in a grid with 3 rows (+ the dummy row that is always present),
+ * because the last '\\' opens a new row.
+ */
+void delEmptyLastRow(MathGridInset & grid)
+{
+ MathGridInset::row_type const row = grid.nrows() - 1;
+ for (MathGridInset::col_type col = 0; col < grid.ncols(); ++col) {
+ if (!grid.cell(grid.index(row, col)).empty())
+ return;
+ }
+ // Copy the row information of the empty row (which would contain the
+ // last hline in the example above) to the dummy row and delete the
+ // empty row.
+ grid.rowinfo(row + 1) = grid.rowinfo(row);
+ grid.delRow(row);
+}
+
+
// These are TeX's catcodes
enum CatCode {
catEscape, // 0 backslash
enum {
- FLAG_BRACE_LAST = 1 << 1, // last closing brace ends the parsing
+ FLAG_ALIGN = 1 << 0, // next & or \\ ends the parsing process
+ FLAG_BRACE_LAST = 1 << 1, // next closing brace ends the parsing
FLAG_RIGHT = 1 << 2, // next \\right ends the parsing process
FLAG_END = 1 << 3, // next \\end ends the parsing process
FLAG_BRACK_LAST = 1 << 4, // next closing bracket ends the parsing
vector<Token> tokens_;
///
unsigned pos_;
+ /// Stack of active environments
+ vector<string> environments_;
};
else if (t.cat() == catAlign) {
//lyxerr << " column now " << (cellcol + 1)
// << " max: " << grid.ncols() << endl;
+ if (flags & FLAG_ALIGN)
+ return;
if (addCol(grid, cellcol))
- cell = &grid.cell(grid.index(cellrow,
- cellcol));
+ cell = &grid.cell(grid.index(cellrow, cellcol));
}
else if (t.cat() == catSuper || t.cat() == catSub) {
return;
}
- string arg = getArg('[', ']');
+ string const arg = getArg('[', ']');
if (!arg.empty())
- nargs = atoi(arg);
+ nargs = convert<int>(arg);
}
else if (t.cs() == "end") {
if (flags & FLAG_END) {
// eat environment name
- //string const name =
- getArg('{', '}');
- // FIXME: check that we ended the correct environment
- return;
- }
- error("found 'end' unexpectedly");
+ string const name = getArg('{', '}');
+ if (environments_.empty())
+ error("'found \\end{" + name +
+ "}' without matching '\\begin{" +
+ name + "}'");
+ else if (name != environments_.back())
+ error("'\\end{" + name +
+ "}' does not match '\\begin{" +
+ environments_.back() + "}'");
+ else {
+ environments_.pop_back();
+ // Delete empty last row in matrix
+ // like insets.
+ // If you abuse MathGridInset for
+ // non-matrix like structures you
+ // probably need to refine this test.
+ // Right now we only have to test for
+ // single line hull insets.
+ if (grid.nrows() > 1)
+ delEmptyLastRow(grid);
+ return;
+ }
+ } else
+ error("found 'end' unexpectedly");
}
else if (t.cs() == ")") {
}
else if (t.cs() == "\\") {
+ if (flags & FLAG_ALIGN)
+ return;
if (addRow(grid, cellrow, getArg('[', ']'))) {
cellcol = 0;
if (grid.asHullInset())
else if (t.cs() == "left") {
skipSpaces();
- string l = getToken().asString();
+ Token const & tl = getToken();
+ // \| and \Vert are equivalent, and MathDelimInset
+ // can't handle \|
+ // FIXME: fix this in MathDelimInset itself!
+ string const l = tl.cs() == "|" ? "Vert" : tl.asString();
MathArray ar;
parse(ar, FLAG_RIGHT, mode);
skipSpaces();
- string r = getToken().asString();
+ Token const & tr = getToken();
+ string const r = tr.cs() == "|" ? "Vert" : tr.asString();
cell->push_back(MathAtom(new MathDelimInset(l, r, ar)));
}
else if (t.cs() == "begin") {
string const name = getArg('{', '}');
+ environments_.push_back(name);
if (name == "array" || name == "subarray") {
string const valign = parse_verbatim_option() + 'c';
}
else if (name == "split" || name == "cases" ||
- name == "gathered" || name == "aligned" ||
- name == "alignedat") {
+ name == "gathered" || name == "aligned") {
+ cell->push_back(createMathInset(name));
+ parse2(cell->back(), FLAG_END, mode, false);
+ }
+
+ else if (name == "alignedat") {
+ // ignore this for a while
+ getArg('{', '}');
cell->push_back(createMathInset(name));
parse2(cell->back(), FLAG_END, mode, false);
}
}
else if (t.cs() == "label") {
+ // FIXME: This is swallowed in inline formulas
string label = parse_verbatim_item();
MathArray ar;
asArray(label, ar);
}
else if (t.cs() == "color") {
- MathAtom at = createMathInset(t.cs());
- parse(at.nucleus()->cell(0), FLAG_ITEM, MathInset::TEXT_MODE);
- parse(at.nucleus()->cell(1), flags, mode);
- cell->push_back(at);
+ string const color = parse_verbatim_item();
+ cell->push_back(MathAtom(new MathColorInset(true, color)));
+ parse(cell->back().nucleus()->cell(0), flags, mode);
+ return;
+ }
+
+ else if (t.cs() == "textcolor") {
+ string const color = parse_verbatim_item();
+ cell->push_back(MathAtom(new MathColorInset(false, color)));
+ parse(cell->back().nucleus()->cell(0), FLAG_ITEM, MathInset::TEXT_MODE);
+ }
+
+ else if (t.cs() == "normalcolor") {
+ cell->push_back(createMathInset(t.cs()));
+ parse(cell->back().nucleus()->cell(0), flags, mode);
return;
}
parse2(cell->back(), FLAG_ITEM, mode, false);
}
+ else if (t.cs() == "xymatrix") {
+ cell->push_back(createMathInset(t.cs()));
+ parse2(cell->back(), FLAG_ITEM, mode, false);
+ }
+
else if (t.cs() == "framebox" || t.cs() == "makebox") {
cell->push_back(createMathInset(t.cs()));
parse(cell->back().nucleus()->cell(0), FLAG_OPTION, MathInset::TEXT_MODE);
if (l) {
if (l->inset == "font") {
cell->push_back(createMathInset(t.cs()));
- parse(cell->back().nucleus()->cell(0), FLAG_ITEM, asMode(mode, l->extra));
+ parse(cell->back().nucleus()->cell(0),
+ FLAG_ITEM, asMode(mode, l->extra));
}
else if (l->inset == "oldfont") {
cell->push_back(createMathInset(t.cs()));
- parse(cell->back().nucleus()->cell(0), flags, asMode(mode, l->extra));
- return;
+ parse(cell->back().nucleus()->cell(0),
+ flags | FLAG_ALIGN, asMode(mode, l->extra));
+ if (prevToken().cat() != catAlign &&
+ prevToken().cs() != "\\")
+ return;
+ putback();
}
else if (l->inset == "style") {
cell->push_back(createMathInset(t.cs()));
- parse(cell->back().nucleus()->cell(0), flags, mode);
- return;
+ parse(cell->back().nucleus()->cell(0),
+ flags | FLAG_ALIGN, mode);
+ if (prevToken().cat() != catAlign &&
+ prevToken().cs() != "\\")
+ return;
+ putback();
}
else {
MathAtom at = createMathInset(t.cs());
for (MathInset::idx_type i = 0; i < at->nargs(); ++i)
- parse(at.nucleus()->cell(i), FLAG_ITEM, asMode(mode, l->extra));
+ parse(at.nucleus()->cell(i),
+ FLAG_ITEM, asMode(mode, l->extra));
cell->push_back(at);
}
}