* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
- * \author André Pönitz
+ * \author André Pönitz
*
* Full author contact details are available in file CREDITS.
*/
#include "InsetMathColor.h"
#include "InsetMathComment.h"
#include "InsetMathDelim.h"
+#include "InsetMathEnsureMath.h"
#include "InsetMathEnv.h"
#include "InsetMathFrac.h"
#include "InsetMathKern.h"
#include "InsetMathRef.h"
#include "InsetMathRoot.h"
#include "InsetMathScript.h"
+#include "InsetMathSpace.h"
#include "InsetMathSplit.h"
#include "InsetMathSqrt.h"
#include "InsetMathTabular.h"
#include "MathMacroArgument.h"
#include "MathSupport.h"
+#include "Buffer.h"
+#include "BufferParams.h"
+#include "Encoding.h"
#include "Lexer.h"
#include "support/debug.h"
}
+docstring const repl(docstring const & oldstr, char_type const c,
+ docstring const & macro, bool textmode = false)
+{
+ docstring newstr;
+ size_t i;
+ size_t j;
+
+ for (i = 0, j = 0; i < oldstr.size(); ++i) {
+ if (c == oldstr[i]) {
+ newstr.append(oldstr, j, i - j);
+ newstr.append(macro);
+ j = i + 1;
+ if (macro.size() > 2 && j < oldstr.size())
+ newstr += (textmode && oldstr[j] == ' ' ? '\\' : ' ');
+ }
+ }
+
+ // Any substitution?
+ if (j == 0)
+ return oldstr;
+
+ newstr.append(oldstr, j, i - j);
+ return newstr;
+}
+
+
+docstring escapeSpecialChars(docstring const & str, bool textmode)
+{
+ docstring const backslash = textmode ? from_ascii("\\textbackslash")
+ : from_ascii("\\backslash");
+ docstring const caret = textmode ? from_ascii("\\textasciicircum")
+ : from_ascii("\\mathcircumflex");
+ docstring const tilde = textmode ? from_ascii("\\textasciitilde")
+ : from_ascii("\\sim");
+
+ return repl(repl(repl(repl(repl(repl(repl(repl(repl(repl(str,
+ '\\', backslash, textmode),
+ '^', caret, textmode),
+ '~', tilde, textmode),
+ '_', from_ascii("\\_")),
+ '$', from_ascii("\\$")),
+ '#', from_ascii("\\#")),
+ '&', from_ascii("\\&")),
+ '%', from_ascii("\\%")),
+ '{', from_ascii("\\{")),
+ '}', from_ascii("\\}"));
+}
+
+
/*!
* Add the row \p cellrow to \p grid.
* \returns wether the row could be added. Adding a row can fail for
public:
///
typedef InsetMath::mode_type mode_type;
+ ///
+ typedef Parse::flags parse_mode;
///
- Parser(Lexer & lex);
+ 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);
+ Parser(istream & is, parse_mode mode, Buffer * buf);
///
- Parser(docstring const & str);
+ Parser(docstring const & str, parse_mode mode, Buffer * buf);
///
bool parse(MathAtom & at);
///
- void parse(MathData & array, unsigned flags, mode_type mode);
+ bool parse(MathData & array, unsigned flags, mode_type mode);
///
- void parse1(InsetMathGrid & grid, unsigned flags, mode_type mode,
+ bool parse1(InsetMathGrid & grid, unsigned flags, mode_type mode,
bool numbered);
///
MathData parse(unsigned flags, mode_type mode);
unsigned pos_;
/// Stack of active environments
vector<docstring> environments_;
+ ///
+ parse_mode mode_;
+ ///
+ bool success_;
+ ///
+ Buffer * buffer_;
};
-Parser::Parser(Lexer & lexer)
- : lineno_(lexer.getLineNo()), pos_(0)
+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)
- : lineno_(0), pos_(0)
+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)
- : lineno_(0), pos_(0)
+Parser::Parser(docstring const & str, parse_mode mode, Buffer * buf)
+ : lineno_(0), pos_(0), mode_(mode), success_(true), buffer_(buf)
{
tokenize(str);
}
void Parser::tokenize(docstring const & buffer)
{
- idocstringstream is(buffer, ios::in | ios::binary);
+ idocstringstream is(mode_ & Parse::VERBATIM
+ ? escapeSpecialChars(buffer, mode_ & Parse::TEXTMODE)
+ : buffer, ios::in | ios::binary);
char_type c;
while (is.get(c)) {
}
case catIgnore: {
- lyxerr << "ignoring a char: " << int(c) << endl;
+ if (!(mode_ & Parse::QUIET))
+ lyxerr << "ignoring a char: " << int(c) << endl;
break;
}
void Parser::error(string const & msg)
{
- lyxerr << "Line ~" << lineno_ << ": Math parse error: " << msg << endl;
- dump();
- //exit(1);
+ success_ = false;
+ if (!(mode_ & Parse::QUIET)) {
+ lyxerr << "Line ~" << lineno_ << ": Math parse error: "
+ << msg << endl;
+ dump();
+ }
}
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) {
- lyxerr << "unusual contents found: " << ar << endl;
- at = MathAtom(new InsetMathPar(ar));
+ if (!(mode_ & Parse::QUIET))
+ lyxerr << "unusual contents found: " << ar << endl;
+ at = MathAtom(new InsetMathPar(buffer_, ar));
//if (at->nargs() > 0)
// at.nucleus()->cell(0) = ar;
//else
// lyxerr << "unusual contents found: " << ar << endl;
- return true;
- }
- at = ar[0];
- return true;
+ success_ = false;
+ } else
+ at = ar[0];
+ return success_;
}
putback();
res += '{' + parse_verbatim_item() + '}';
} else
- res += t.asString();
+ res += t.asInput();
}
}
return res;
res += '{' + parse_verbatim_item() + '}';
}
else
- res += t.asString();
+ res += t.asInput();
}
}
return res;
MathData Parser::parse(unsigned flags, mode_type mode)
{
- MathData ar;
+ MathData ar(buffer_);
parse(ar, flags, mode);
return ar;
}
-void Parser::parse(MathData & array, 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_;
}
}
-void Parser::parse1(InsetMathGrid & grid, unsigned flags,
+bool Parser::parse1(InsetMathGrid & grid, unsigned flags,
const mode_type mode, const bool numbered)
{
int limits = 0;
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);
// skip the brace and collect everything to the next matching
// closing brace
parse1(grid, FLAG_BRACE_LAST, mode, numbered);
- return;
+ return success_;
}
// handle only this single token, leave the loop if done
if (t.cat() != catBegin) {
error("opening brace expected");
- return;
+ return success_;
}
// skip the brace and collect everything to the next matching
// no option found, put back token and we are done
putback();
}
- return;
+ return success_;
}
//
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();
- cell->push_back(MathAtom(new InsetMathHull(hullSimple)));
- parse2(cell->back(), FLAG_SIMPLE, InsetMath::MATH_MODE, false);
+ if (mode == InsetMath::UNDECIDED_MODE) {
+ 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(buf)));
+ parse(cell->back().nucleus()->cell(0), FLAG_SIMPLE, InsetMath::MATH_MODE);
+ }
}
}
else if (flags & FLAG_SIMPLE) {
// this is the end of the formula
- return;
+ return success_;
}
else {
else if (t.cat() == catEnd) {
if (flags & FLAG_BRACE_LAST)
- return;
+ return success_;
error("found '}' unexpectedly");
- //BOOST_ASSERT(false);
+ //LASSERT(false, /**/);
//add(cell, '}', LM_TC_TEX);
}
//lyxerr << " column now " << (cellcol + 1)
// << " max: " << grid.ncols() << endl;
if (flags & FLAG_ALIGN)
- return;
+ return success_;
if (addCol(grid, cellcol))
cell = &grid.cell(grid.index(cellrow, cellcol));
}
// 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
else if (t.character() == ']' && (flags & FLAG_BRACK_LAST)) {
//lyxerr << "finished reading option" << endl;
- return;
+ return success_;
}
- else if (t.cat() == catOther)
- cell->push_back(MathAtom(new InsetMathChar(t.character())));
+ else if (t.cat() == catOther) {
+ char_type c = t.character();
+ if (isAsciiOrMathAlpha(c)
+ || mode_ & Parse::VERBATIM
+ || !(mode_ & Parse::USETEXT)
+ || mode == InsetMath::TEXT_MODE) {
+ cell->push_back(MathAtom(new InsetMathChar(c)));
+ } else {
+ MathAtom at = createInsetMath("text", buf);
+ at.nucleus()->cell(0).push_back(MathAtom(new InsetMathChar(c)));
+ while (nextToken().cat() == catOther
+ && !isAsciiOrMathAlpha(nextToken().character())) {
+ c = getToken().character();
+ at.nucleus()->cell(0).push_back(MathAtom(new InsetMathChar(c)));
+ }
+ cell->push_back(at);
+ }
+ }
else if (t.cat() == catComment) {
docstring s;
break;
s += t.asString();
}
- cell->push_back(MathAtom(new InsetMathComment(s)));
+ cell->push_back(MathAtom(new InsetMathComment(buf, s)));
skipSpaces();
}
cell->back().nucleus()->lock(true);
}
- else if (t.cs() == "def" ||
- t.cs() == "newcommand" ||
- t.cs() == "renewcommand" ||
- t.cs() == "newlyxcommand")
- {
- MacroType type = MacroTypeNewcommand;
- if (t.cs() == "def")
- type = MacroTypeDef;
- docstring name;
+ else if ((t.cs() == "global" && nextToken().cs() == "def") ||
+ t.cs() == "def") {
+ if (t.cs() == "global")
+ getToken();
+
+ // get name
+ docstring name = getToken().cs();
+
+ // read parameters
int nargs = 0;
+ docstring pars;
+ while (good() && nextToken().cat() != catBegin) {
+ pars += getToken().cs();
+ ++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<MathData>(), def, display)));
+
+ if (buf && (mode_ & Parse::TRACKMACRO))
+ buf->usermacros.insert(name);
+ }
+
+ else if (t.cs() == "newcommand" ||
+ t.cs() == "renewcommand" ||
+ t.cs() == "newlyxcommand") {
+ // get name
+ if (getToken().cat() != catBegin) {
+ error("'{' in \\newcommand expected (1) ");
+ return success_;
+ }
+ docstring name = getToken().cs();
+ if (getToken().cat() != catEnd) {
+ error("'}' in \\newcommand expected");
+ return success_;
+ }
+
+ // get arity
+ docstring const arg = getArg('[', ']');
+ int nargs = 0;
+ if (!arg.empty())
+ nargs = convert<int>(arg);
+
+ // optional argument given?
+ skipSpaces();
int optionals = 0;
vector<MathData> optionalValues;
- if (type == MacroTypeDef) {
- // get name
- name = getToken().cs();
-
- // read parameter
- docstring pars;
- while (good() && nextToken().cat() != catBegin) {
- pars += getToken().cs();
- ++nargs;
- }
- nargs /= 2;
- //lyxerr << "read \\def parameter list '" << pars << "'" << endl;
-
- } else {
- if (getToken().cat() != catBegin) {
- error("'{' in \\newcommand expected (1) ");
- return;
- }
+ while (nextToken().character() == '[') {
+ getToken();
+ optionalValues.push_back(MathData());
+ 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)));
+ 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}
+ // get name
+ docstring name;
+ if (nextToken().cat() == catBegin) {
+ getToken();
name = getToken().cs();
-
if (getToken().cat() != catEnd) {
- error("'}' in \\newcommand expected");
- return;
+ error("'}' in \\newcommandx expected");
+ return success_;
}
-
- docstring const arg = getArg('[', ']');
- if (!arg.empty())
- nargs = convert<int>(arg);
-
- // optional argument given?
+ } else
+ name = getToken().cs();
+
+ // get arity
+ docstring const arg = getArg('[', ']');
+ if (arg.empty()) {
+ error("[num] in \\newcommandx expected");
+ return success_;
+ }
+ int nargs = convert<int>(arg);
+
+ // get options
+ int optionals = 0;
+ vector<MathData> optionalValues;
+ if (nextToken().character() == '[') {
+ // skip '['
+ getToken();
+
+ // handle 'opt=value' options, separated by ','.
skipSpaces();
- while (nextToken().character() == '[') {
- getToken();
- optionalValues.push_back(MathData());
- parse(optionalValues[optionals], FLAG_BRACK_LAST, mode);
- ++optionals;
+ while (nextToken().character() != ']' && good()) {
+ if (nextToken().character() >= '1'
+ && nextToken().character() <= '9') {
+ // optional value -> get parameter number
+ int n = getChar() - '0';
+ if (n > nargs) {
+ error("Arity of \\newcommandx too low "
+ "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);
+ optionalValues[n - 1].clear();
+ while (nextToken().character() != ']'
+ && nextToken().character() != ',') {
+ MathData data;
+ parse(data, FLAG_ITEM, InsetMath::UNDECIDED_MODE);
+ optionalValues[n - 1].append(data);
+ }
+ optionals = max(n, optionals);
+ } 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;
+ if (nextToken().character() == '=') {
+ getToken();
+ while (nextToken().character() != ']'
+ && nextToken().character() != ',')
+ parse(value, FLAG_ITEM,
+ InsetMath::UNDECIDED_MODE);
+ }
+ } else {
+ error("option for \\newcommandx expected");
+ return success_;
+ }
+
+ // skip komma
+ skipSpaces();
+ if (nextToken().character() == ',') {
+ getChar();
+ skipSpaces();
+ } else if (nextToken().character() != ']') {
+ error("Expecting ',' or ']' in options "
+ "of \\newcommandx");
+ return success_;
+ }
}
+
+ // skip ']'
+ if (!good())
+ return success_;
+ getToken();
}
+ // get definition
MathData def;
parse(def, FLAG_ITEM, InsetMath::UNDECIDED_MODE);
if (nextToken().cat() == catBegin)
parse(display, FLAG_ITEM, InsetMath::MATH_MODE);
- cell->push_back(MathAtom(new MathMacroTemplate(name, nargs, optionals, type,
- 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() == "(") {
- cell->push_back(MathAtom(new InsetMathHull(hullSimple)));
+ 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);
}
else if (t.cs() == "[") {
- cell->push_back(MathAtom(new InsetMathHull(hullEquation)));
+ if (mode != InsetMath::UNDECIDED_MODE) {
+ error("bad math environment");
+ break;
+ }
+ cell->push_back(MathAtom(new InsetMathHull(buf, hullEquation)));
parse2(cell->back(), FLAG_EQUATION, InsetMath::MATH_MODE, false);
}
// single line hull insets.
if (grid.nrows() > 1)
delEmptyLastRow(grid);
- return;
+ return success_;
}
} else
error("found 'end' unexpectedly");
else if (t.cs() == ")") {
if (flags & FLAG_SIMPLE2)
- return;
+ return success_;
error("found '\\)' unexpectedly");
}
else if (t.cs() == "]") {
if (flags & FLAG_EQUATION)
- return;
+ return success_;
error("found '\\]' unexpectedly");
}
else if (t.cs() == "\\") {
if (flags & FLAG_ALIGN)
- return;
+ return success_;
bool added = false;
if (nextToken().asInput() == "*") {
getToken();
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
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);
}
}
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);
}
}
+
else if (t.cs() == "unitfrac") {
// 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)));
+ 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);
}
+ else if (t.cs() == "cfrac") {
+ // allowed formats are \cfrac[pos]{num}{denom}
+ docstring const arg = getArg('[', ']');
+ //lyxerr << "got so far: '" << arg << "'" << endl;
+ if (arg == "l")
+ cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRACLEFT)));
+ else if (arg == "r")
+ cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRACRIGHT)));
+ else if (arg.empty() || arg == "c")
+ cell->push_back(MathAtom(new InsetMathFrac(buf, InsetMathFrac::CFRAC)));
+ else {
+ error("found invalid optional argument");
+ break;
+ }
+ 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() == "prettyref" ||
- t.cs() == "pageref" || t.cs() == "vpageref" || t.cs() == "vref") {
- cell->push_back(MathAtom(new InsetMathRef(t.cs())));
+ 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())));
parse(cell->back().nucleus()->cell(1), FLAG_OPTION, mode);
parse(cell->back().nucleus()->cell(0), FLAG_ITEM, mode);
}
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") {
if (flags & FLAG_RIGHT)
- return;
+ return success_;
//lyxerr << "got so far: '" << cell << "'" << endl;
error("Unmatched right delimiter");
- return;
+ return success_;
}
else if (t.cs() == "begin") {
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, (char)valign[0], halign)));
+ cell->push_back(MathAtom(new InsetMathArray(buf, name,
+ InsetMathGrid::guessColumns(halign), 1, (char)valign[0], halign)));
parse2(cell->back(), FLAG_END, mode, false);
}
else if (name == "tabular") {
docstring const valign = parse_verbatim_option() + 'c';
docstring const halign = parse_verbatim_item();
- cell->push_back(MathAtom(new InsetMathTabular(name, (char)valign[0], halign)));
+ 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);
}
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") {
- cell->push_back(MathAtom(new InsetMathHull(hullSimple)));
+ 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);
}
else if (name == "equation" || name == "equation*"
|| name == "displaymath") {
- cell->push_back(MathAtom(new InsetMathHull(hullEquation)));
+ if (mode != InsetMath::UNDECIDED_MODE) {
+ error("bad math environment");
+ break;
+ }
+ cell->push_back(MathAtom(new InsetMathHull(buf, hullEquation)));
parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, (name == "equation"));
}
else if (name == "eqnarray" || name == "eqnarray*") {
- cell->push_back(MathAtom(new InsetMathHull(hullEqnArray)));
+ if (mode != InsetMath::UNDECIDED_MODE) {
+ error("bad math environment");
+ break;
+ }
+ cell->push_back(MathAtom(new InsetMathHull(buf, hullEqnArray)));
parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name));
}
else if (name == "align" || name == "align*") {
- cell->push_back(MathAtom(new InsetMathHull(hullAlign)));
+ if (mode != InsetMath::UNDECIDED_MODE) {
+ error("bad math environment");
+ break;
+ }
+ cell->push_back(MathAtom(new InsetMathHull(buf, hullAlign)));
parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name));
}
else if (name == "flalign" || name == "flalign*") {
- cell->push_back(MathAtom(new InsetMathHull(hullFlAlign)));
+ if (mode != InsetMath::UNDECIDED_MODE) {
+ error("bad math environment");
+ break;
+ }
+ cell->push_back(MathAtom(new InsetMathHull(buf, hullFlAlign)));
parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name));
}
else if (name == "alignat" || name == "alignat*") {
+ if (mode != InsetMath::UNDECIDED_MODE) {
+ error("bad math environment");
+ break;
+ }
// 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));
}
else if (name == "xalignat" || name == "xalignat*") {
+ if (mode != InsetMath::UNDECIDED_MODE) {
+ error("bad math environment");
+ break;
+ }
// 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));
}
else if (name == "xxalignat") {
+ if (mode != InsetMath::UNDECIDED_MODE) {
+ error("bad math environment");
+ break;
+ }
// 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));
}
else if (name == "multline" || name == "multline*") {
- cell->push_back(MathAtom(new InsetMathHull(hullMultline)));
+ if (mode != InsetMath::UNDECIDED_MODE) {
+ error("bad math environment");
+ break;
+ }
+ cell->push_back(MathAtom(new InsetMathHull(buf, hullMultline)));
parse2(cell->back(), FLAG_END, InsetMath::MATH_MODE, !stared(name));
}
else if (name == "gather" || name == "gather*") {
- cell->push_back(MathAtom(new InsetMathHull(hullGather)));
+ if (mode != InsetMath::UNDECIDED_MODE) {
+ error("bad math environment");
+ break;
+ }
+ 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 {
- dump();
- lyxerr << "found math environment `" << to_utf8(name)
- << "' in symbols file with unsupported inset `"
- << to_utf8(l->inset) << "'." << endl;
+ success_ = false;
+ if (!(mode_ & Parse::QUIET)) {
+ dump();
+ lyxerr << "found math environment `"
+ << to_utf8(name)
+ << "' in symbols file with unsupported inset `"
+ << to_utf8(l->inset)
+ << "'." << 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);
}
}
else {
- dump();
- lyxerr << "found unknown math environment '" << to_utf8(name)
- << "'" << endl;
+ success_ = false;
+ if (!(mode_ & Parse::QUIET)) {
+ dump();
+ lyxerr << "found unknown math environment '"
+ << 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);
}
}
else if (t.cs() == "kern") {
// FIXME: A hack...
docstring s;
+ int num_tokens = 0;
while (true) {
Token const & t = getToken();
+ ++num_tokens;
if (!good()) {
- putback();
+ s.clear();
+ while (num_tokens--)
+ putback();
break;
}
s += t.character();
if (isValidLength(to_utf8(s)))
break;
}
- cell->push_back(MathAtom(new InsetMathKern(s)));
+ if (s.empty())
+ cell->push_back(MathAtom(new InsetMathKern));
+ else
+ cell->push_back(MathAtom(new InsetMathKern(s)));
}
else if (t.cs() == "label") {
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)));
}
}
- else if (t.cs() == "choose" || t.cs() == "over" || t.cs() == "atop") {
- MathAtom at = createInsetMath(t.cs());
+ else if (t.cs() == "choose" || t.cs() == "over"
+ || t.cs() == "atop" || t.cs() == "brace"
+ || t.cs() == "brack") {
+ MathAtom at = createInsetMath(t.cs(), buf);
at.nucleus()->cell(0) = *cell;
cell->clear();
parse(at.nucleus()->cell(1), flags, mode);
cell->push_back(at);
- return;
+ return success_;
}
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;
+ 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;
+ 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);
}
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);
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() != '*') {
+ 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)));
+ else {
+ // Since the Length class cannot use length variables
+ // we must not create an InsetMathSpace.
+ cell->push_back(MathAtom(new MathMacro(buf, name)));
+ MathData ar;
+ mathed_parse_cell(ar, '{' + arg + '}', mode_);
+ cell->append(ar);
+ }
+ }
+
#if 0
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);
}
}
#endif
+ else if (t.cs() == "lyxmathsym") {
+ skipSpaces();
+ if (getToken().cat() != catBegin) {
+ error("'{' expected in \\" + t.cs());
+ return success_;
+ }
+ int count = 0;
+ docstring cmd;
+ CatCode cat = nextToken().cat();
+ while (good() && (count || cat != catEnd)) {
+ if (cat == catBegin)
+ ++count;
+ else if (cat == catEnd)
+ --count;
+ cmd += getToken().asInput();
+ cat = nextToken().cat();
+ }
+ if (getToken().cat() != catEnd) {
+ error("'}' expected in \\" + t.cs());
+ return success_;
+ }
+ docstring rem;
+ do {
+ cmd = Encodings::fromLaTeXCommand(cmd, rem);
+ for (size_t i = 0; i < cmd.size(); ++i)
+ cell->push_back(MathAtom(new InsetMathChar(cmd[i])));
+ if (rem.size()) {
+ char_type c = rem[0];
+ cell->push_back(MathAtom(new InsetMathChar(c)));
+ cmd = rem.substr(1);
+ rem.clear();
+ } else
+ cmd.clear();
+ } while (cmd.size());
+ }
+
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();
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 &&
prevToken().cs() != "\\")
- return;
+ return success_;
putback();
}
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 &&
prevToken().cs() != "\\")
- return;
+ return success_;
putback();
}
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));
}
else {
- MathAtom at = createInsetMath(t.cs());
- InsetMath::mode_type m = mode;
- //if (m == InsetMath::UNDECIDED_MODE)
- //lyxerr << "default creation: m1: " << m << endl;
- if (at->currentMode() != InsetMath::UNDECIDED_MODE)
- m = at->currentMode();
- //lyxerr << "default creation: m2: " << m << endl;
- InsetMath::idx_type start = 0;
- // this fails on \bigg[...\bigg]
- //MathData opt;
- //parse(opt, FLAG_OPTION, InsetMath::VERBATIM_MODE);
- //if (opt.size()) {
- // start = 1;
- // at.nucleus()->cell(0) = opt;
- //}
- for (InsetMath::idx_type i = start; i < at->nargs(); ++i) {
- parse(at.nucleus()->cell(i), FLAG_ITEM, m);
- skipSpaces();
+ bool is_unicode_symbol = false;
+ if (mode == InsetMath::TEXT_MODE && !is_user_macro) {
+ int num_tokens = 0;
+ docstring cmd = prevToken().asInput();
+ CatCode cat = nextToken().cat();
+ if (cat == catBegin) {
+ int count = 0;
+ while (good() && (count || cat != catEnd)) {
+ cat = nextToken().cat();
+ cmd += getToken().asInput();
+ ++num_tokens;
+ if (cat == catBegin)
+ ++count;
+ else if (cat == catEnd)
+ --count;
+ }
+ }
+ bool is_combining;
+ char_type c =
+ Encodings::fromLaTeXCommand(cmd, is_combining);
+ if (is_combining) {
+ if (cat == catLetter)
+ cmd += '{';
+ cmd += getToken().asInput();
+ ++num_tokens;
+ if (cat == catLetter)
+ cmd += '}';
+ c = Encodings::fromLaTeXCommand(cmd, is_combining);
+ }
+ if (c) {
+ is_unicode_symbol = true;
+ cell->push_back(MathAtom(new InsetMathChar(c)));
+ } else {
+ while (num_tokens--)
+ putback();
+ }
+ }
+ if (!is_unicode_symbol) {
+ 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;
+ if (at->currentMode() != InsetMath::UNDECIDED_MODE)
+ m = at->currentMode();
+ //lyxerr << "default creation: m2: " << m << endl;
+ InsetMath::idx_type start = 0;
+ // this fails on \bigg[...\bigg]
+ //MathData opt;
+ //parse(opt, FLAG_OPTION, InsetMath::VERBATIM_MODE);
+ //if (opt.size()) {
+ // start = 1;
+ // at.nucleus()->cell(0) = opt;
+ //}
+ for (InsetMath::idx_type i = start; i < at->nargs(); ++i) {
+ parse(at.nucleus()->cell(i), FLAG_ITEM, m);
+ skipSpaces();
+ }
+ cell->push_back(at);
}
- cell->push_back(at);
}
}
break;
}
}
+ return success_;
}
} // anonymous namespace
-void mathed_parse_cell(MathData & ar, docstring const & str)
+bool mathed_parse_cell(MathData & ar, docstring const & str, Parse::flags f)
{
- Parser(str).parse(ar, 0, InsetMath::MATH_MODE);
+ return Parser(str, f, ar.buffer()).parse(ar, 0, f & Parse::TEXTMODE ?
+ InsetMath::TEXT_MODE : InsetMath::MATH_MODE);
}
-void mathed_parse_cell(MathData & ar, istream & is)
+bool mathed_parse_cell(MathData & ar, istream & is, Parse::flags f)
{
- Parser(is).parse(ar, 0, InsetMath::MATH_MODE);
+ 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)
+bool mathed_parse_normal(Buffer * buf, MathAtom & t, docstring const & str,
+ Parse::flags f)
{
- return Parser(str).parse(t);
+ return Parser(str, f, buf).parse(t);
}
-bool mathed_parse_normal(MathAtom & t, Lexer & lex)
+bool mathed_parse_normal(Buffer * buf, MathAtom & t, Lexer & lex,
+ Parse::flags f)
{
- return Parser(lex).parse(t);
+ return Parser(lex, f, buf).parse(t);
}
-void mathed_parse_normal(InsetMathGrid & grid, docstring const & str)
+bool mathed_parse_normal(InsetMathGrid & grid, docstring const & str,
+ Parse::flags f)
{
- Parser(str).parse1(grid, 0, InsetMath::MATH_MODE, false);
+ return Parser(str, f, &grid.buffer()).parse1(grid, 0, f & Parse::TEXTMODE ?
+ InsetMath::TEXT_MODE : InsetMath::MATH_MODE, false);
}