X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2FMathExtern.cpp;h=ee2004b5088644679fe6dee20eb44f6197f4cef6;hb=25d64bf43aba78a1ed20c88dfdc4cac269b53985;hp=36ca80104ea63412c4bc7c996c8e442b83f552a5;hpb=f497296c30e6da2f97b16da8ad1c9e96feffb16b;p=lyx.git diff --git a/src/mathed/MathExtern.cpp b/src/mathed/MathExtern.cpp index 36ca80104e..ee2004b508 100644 --- a/src/mathed/MathExtern.cpp +++ b/src/mathed/MathExtern.cpp @@ -3,22 +3,23 @@ * 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. */ // This file contains most of the magic that extracts "context -// information" from the unstructered layout-oriented stuff in an -// MathArray. +// information" from the unstructered layout-oriented stuff in +// MathData. #include #include "MathExtern.h" + +#include "InsetMathAMSArray.h" #include "InsetMathArray.h" #include "InsetMathChar.h" #include "InsetMathDelim.h" -#include "MathData.h" #include "InsetMathDiff.h" #include "InsetMathExFunc.h" #include "InsetMathExInt.h" @@ -26,45 +27,56 @@ #include "InsetMathFrac.h" #include "InsetMathLim.h" #include "InsetMathMatrix.h" -#include "MathStream.h" #include "InsetMathNumber.h" #include "InsetMathScript.h" #include "InsetMathString.h" #include "InsetMathSymbol.h" +#include "MathData.h" #include "MathParser.h" -#include "debug.h" +#include "MathStream.h" + +#include "Encoding.h" + +#include "support/debug.h" +#include "support/docstream.h" +#include "support/FileName.h" #include "support/filetools.h" +#include "support/gettext.h" #include "support/lstrings.h" -#include "support/lyxlib.h" -#include "frontends/controllers/ControlMath.h" +#include "support/TempFile.h" +#include "support/textutils.h" +#include "support/unique_ptr.h" #include #include #include +#include +using namespace std; +using namespace lyx::support; namespace lyx { -using support::cmd_ret; -using support::getVectorFromString; -using support::libFileSearch; -using support::runCommand; -using support::FileName; -using support::quoteName; -using support::tempName; -using support::unlink; -using support::subst; - -using frontend::function_names; - -using std::endl; -using std::find_if; -using std::auto_ptr; -using std::istringstream; -using std::ostream; -using std::swap; -using std::string; -using std::vector; +namespace { + +enum ExternalMath { + HTML, + MAPLE, + MAXIMA, + MATHEMATICA, + MATHML, + OCTAVE +}; + + +static char const * function_names[] = { + "arccos", "arcsin", "arctan", "arg", "bmod", + "cos", "cosh", "cot", "coth", "csc", "deg", + "det", "dim", "exp", "gcd", "hom", "inf", "ker", + "lg", "lim", "liminf", "limsup", "ln", "log", + "max", "min", "sec", "sin", "sinh", "sup", + "tan", "tanh", "Pr", 0 +}; static size_t const npos = lyx::docstring::npos; @@ -72,14 +84,14 @@ static size_t const npos = lyx::docstring::npos; typedef bool TestItemFunc(MathAtom const &); // define a function for replacing subexpressions -typedef MathAtom ReplaceArgumentFunc(const MathArray & ar); +typedef MathAtom ReplaceArgumentFunc(const MathData & ar); // try to extract a super/subscript // modify iterator position to point behind the thing -bool extractScript(MathArray & ar, - MathArray::iterator & pos, MathArray::iterator last, bool superscript) +bool extractScript(MathData & ar, + MathData::iterator & pos, MathData::iterator last, bool superscript) { // nothing to get here if (pos == last) @@ -102,8 +114,9 @@ bool extractScript(MathArray & ar, // try to extract an "argument" to some function. // returns position behind the argument -MathArray::iterator extractArgument(MathArray & ar, - MathArray::iterator pos, MathArray::iterator last, bool function = false) +MathData::iterator extractArgument(MathData & ar, + MathData::iterator pos, MathData::iterator last, + ExternalMath kind, bool function = false) { // nothing to get here if (pos == last) @@ -112,10 +125,12 @@ MathArray::iterator extractArgument(MathArray & ar, // something delimited _is_ an argument if ((*pos)->asDelimInset()) { // leave out delimiters if this is a function argument - if (function) { - MathArray const & arg = (*pos)->asDelimInset()->cell(0); - MathArray::const_iterator cur = arg.begin(); - MathArray::const_iterator end = arg.end(); + // unless we are doing MathML, in which case we do want + // the delimiters + if (function && kind != MATHML && kind != HTML) { + MathData const & arg = (*pos)->asDelimInset()->cell(0); + MathData::const_iterator cur = arg.begin(); + MathData::const_iterator end = arg.end(); while (cur != end) ar.push_back(*cur++); } else @@ -146,7 +161,7 @@ MathArray::iterator extractArgument(MathArray & ar, // but it might be more than that. // FIXME: not implemented - //for (MathArray::iterator it = pos + 1; it != last; ++it) { + //for (MathData::iterator it = pos + 1; it != last; ++it) { // // always take the first thing, no matter // if (it == pos) { // ar.push_back(*it); @@ -160,7 +175,7 @@ MathArray::iterator extractArgument(MathArray & ar, // returns sequence of char with same code starting at it up to end // it might be less, though... docstring charSequence - (MathArray::const_iterator it, MathArray::const_iterator end) + (MathData::const_iterator it, MathData::const_iterator end) { docstring s; for (; it != end && (*it)->asCharInset(); ++it) @@ -169,7 +184,7 @@ docstring charSequence } -void extractStrings(MathArray & ar) +void extractStrings(MathData & ar) { //lyxerr << "\nStrings from: " << ar << endl; for (size_t i = 0; i < ar.size(); ++i) { @@ -183,25 +198,36 @@ void extractStrings(MathArray & ar) } -void extractMatrices(MathArray & ar) +void extractMatrices(MathData & ar) { //lyxerr << "\nMatrices from: " << ar << endl; // first pass for explicitly delimited stuff for (size_t i = 0; i < ar.size(); ++i) { - if (!ar[i]->asDelimInset()) + InsetMathDelim const * const inset = ar[i]->asDelimInset(); + if (!inset) continue; - MathArray const & arr = ar[i]->asDelimInset()->cell(0); + MathData const & arr = inset->cell(0); if (arr.size() != 1) continue; if (!arr.front()->asGridInset()) continue; - ar[i] = MathAtom(new InsetMathMatrix(*(arr.front()->asGridInset()))); + ar[i] = MathAtom(new InsetMathMatrix(*(arr.front()->asGridInset()), + inset->left_, inset->right_)); } // second pass for AMS "pmatrix" etc - for (size_t i = 0; i < ar.size(); ++i) - if (ar[i]->asAMSArrayInset()) - ar[i] = MathAtom(new InsetMathMatrix(*(ar[i]->asGridInset()))); + for (size_t i = 0; i < ar.size(); ++i) { + InsetMathAMSArray const * const inset = ar[i]->asAMSArrayInset(); + if (inset) { + string left = inset->name_left(); + if (left == "Vert") + left = "["; + string right = inset->name_right(); + if (right == "Vert") + right = "]"; + ar[i] = MathAtom(new InsetMathMatrix(*inset, from_ascii(left), from_ascii(right))); + } + } //lyxerr << "\nMatrices to: " << ar << endl; } @@ -224,7 +250,7 @@ bool extractString(MathAtom const & at, docstring & str) // is this a known function? bool isKnownFunction(docstring const & str) { - for (int i = 0; *function_names[i]; ++i) { + for (int i = 0; function_names[i]; ++i) { if (str == function_names[i]) return true; } @@ -246,7 +272,7 @@ bool extractFunctionName(MathAtom const & at, docstring & str) } if (at->asFontInset() && at->name() == "mathrm") { // assume it is well known... - MathArray const & ar = at->asFontInset()->cell(0); + MathData const & ar = at->asFontInset()->cell(0); str = charSequence(ar.begin(), ar.end()); return ar.size() == str.size(); } @@ -254,23 +280,6 @@ bool extractFunctionName(MathAtom const & at, docstring & str) } -// convert this inset somehow to a number -bool extractNumber(MathArray const & ar, int & i) -{ - idocstringstream is(charSequence(ar.begin(), ar.end())); - is >> i; - return is; -} - - -bool extractNumber(MathArray const & ar, double & d) -{ - idocstringstream is(charSequence(ar.begin(), ar.end())); - is >> d; - return is; -} - - bool testString(MathAtom const & at, docstring const & str) { docstring s; @@ -284,9 +293,9 @@ bool testString(MathAtom const & at, char const * const str) } // search end of nested sequence -MathArray::iterator endNestSearch( - MathArray::iterator it, - MathArray::iterator last, +MathData::iterator endNestSearch( + MathData::iterator it, + MathData::iterator last, TestItemFunc testOpen, TestItemFunc testClose ) @@ -305,12 +314,12 @@ MathArray::iterator endNestSearch( // replace nested sequences by a real Insets void replaceNested( - MathArray & ar, + MathData & ar, TestItemFunc testOpen, TestItemFunc testClose, - ReplaceArgumentFunc replaceArg -) + ReplaceArgumentFunc replaceArg) { + Buffer * buf = ar.buffer(); // use indices rather than iterators for the loop because we are going // to modify the array. for (size_t i = 0; i < ar.size(); ++i) { @@ -319,13 +328,13 @@ void replaceNested( continue; // search end of sequence - MathArray::iterator it = ar.begin() + i; - MathArray::iterator jt = endNestSearch(it, ar.end(), testOpen, testClose); + MathData::iterator it = ar.begin() + i; + MathData::iterator jt = endNestSearch(it, ar.end(), testOpen, testClose); if (jt == ar.end()) continue; // replace the original stuff by the new inset - ar[i] = replaceArg(MathArray(it + 1, jt)); + ar[i] = replaceArg(MathData(buf, it + 1, jt)); ar.erase(it + 1, jt + 1); } } @@ -337,8 +346,9 @@ void replaceNested( // front of super... // -void splitScripts(MathArray & ar) +void splitScripts(MathData & ar) { + Buffer * buf = ar.buffer(); //lyxerr << "\nScripts from: " << ar << endl; for (size_t i = 0; i < ar.size(); ++i) { InsetMathScript const * script = ar[i]->asScriptInset(); @@ -348,7 +358,7 @@ void splitScripts(MathArray & ar) continue; // we must have a nucleus if we only have a superscript - if (!script->hasDown() && script->nuc().size() == 0) + if (!script->hasDown() && script->nuc().empty()) continue; if (script->nuc().size() == 1) { @@ -361,15 +371,15 @@ void splitScripts(MathArray & ar) // create extra script inset and move superscript over InsetMathScript * p = ar[i].nucleus()->asScriptInset(); - auto_ptr q(new InsetMathScript(true)); + auto q = make_unique(buf, true); swap(q->up(), p->up()); p->removeScript(true); // if we don't have a subscript, get rid of the ScriptInset if (!script->hasDown()) { - MathArray arg(p->nuc()); - MathArray::const_iterator it = arg.begin(); - MathArray::const_iterator et = arg.end(); + MathData arg(p->nuc()); + MathData::const_iterator it = arg.begin(); + MathData::const_iterator et = arg.end(); ar.erase(i); while (it != et) ar.insert(i++, *it++); @@ -387,8 +397,9 @@ void splitScripts(MathArray & ar) // extract exp(...) // -void extractExps(MathArray & ar) +void extractExps(MathData & ar) { + Buffer * buf = ar.buffer(); //lyxerr << "\nExps from: " << ar << endl; for (size_t i = 0; i + 1 < ar.size(); ++i) { // is this 'e'? @@ -401,7 +412,7 @@ void extractExps(MathArray & ar) continue; // create a proper exp-inset as replacement - ar[i] = MathAtom(new InsetMathExFunc(from_ascii("exp"), sup->cell(1))); + ar[i] = MathAtom(new InsetMathExFunc(buf, from_ascii("exp"), sup->cell(1))); ar.erase(i + 1); } //lyxerr << "\nExps to: " << ar << endl; @@ -411,16 +422,17 @@ void extractExps(MathArray & ar) // // extract det(...) from |matrix| // -void extractDets(MathArray & ar) +void extractDets(MathData & ar) { + Buffer * buf = ar.buffer(); //lyxerr << "\ndet from: " << ar << endl; - for (MathArray::iterator it = ar.begin(); it != ar.end(); ++it) { + for (MathData::iterator it = ar.begin(); it != ar.end(); ++it) { InsetMathDelim const * del = (*it)->asDelimInset(); if (!del) continue; if (!del->isAbs()) continue; - *it = MathAtom(new InsetMathExFunc(from_ascii("det"), del->cell(0))); + *it = MathAtom(new InsetMathExFunc(buf, from_ascii("det"), del->cell(0))); } //lyxerr << "\ndet to: " << ar << endl; } @@ -438,7 +450,7 @@ bool isDigitOrSimilar(char_type c) // returns sequence of digits docstring digitSequence - (MathArray::const_iterator it, MathArray::const_iterator end) + (MathData::const_iterator it, MathData::const_iterator end) { docstring s; for (; it != end && (*it)->asCharInset(); ++it) { @@ -450,7 +462,7 @@ docstring digitSequence } -void extractNumbers(MathArray & ar) +void extractNumbers(MathData & ar) { //lyxerr << "\nNumbers from: " << ar << endl; for (size_t i = 0; i < ar.size(); ++i) { @@ -485,9 +497,10 @@ bool testCloseParen(MathAtom const & at) } -MathAtom replaceParenDelims(const MathArray & ar) +MathAtom replaceParenDelims(const MathData & ar) { - return MathAtom(new InsetMathDelim(from_ascii("("), from_ascii(")"), ar)); + return MathAtom(new InsetMathDelim(const_cast(ar.buffer()), + from_ascii("("), from_ascii(")"), ar)); } @@ -503,14 +516,15 @@ bool testCloseBracket(MathAtom const & at) } -MathAtom replaceBracketDelims(const MathArray & ar) +MathAtom replaceBracketDelims(const MathData & ar) { - return MathAtom(new InsetMathDelim(from_ascii("["), from_ascii("]"), ar)); + return MathAtom(new InsetMathDelim(const_cast(ar.buffer()), + from_ascii("["), from_ascii("]"), ar)); } // replace '('...')' and '['...']' sequences by a real InsetMathDelim -void extractDelims(MathArray & ar) +void extractDelims(MathData & ar) { //lyxerr << "\nDelims from: " << ar << endl; replaceNested(ar, testOpenParen, testCloseParen, replaceParenDelims); @@ -527,23 +541,45 @@ void extractDelims(MathArray & ar) // replace 'f' '(...)' and 'f' '^n' '(...)' sequences by a real InsetMathExFunc // assume 'extractDelims' ran before -void extractFunctions(MathArray & ar) +void extractFunctions(MathData & ar, ExternalMath kind) { + // FIXME From what I can see, this is quite broken right now, for reasons + // I will note below. (RGH) + // we need at least two items... if (ar.size() < 2) return; + Buffer * buf = ar.buffer(); + //lyxerr << "\nFunctions from: " << ar << endl; for (size_t i = 0; i + 1 < ar.size(); ++i) { - MathArray::iterator it = ar.begin() + i; - MathArray::iterator jt = it + 1; + MathData::iterator it = ar.begin() + i; + MathData::iterator jt = it + 1; docstring name; // is it a function? // it certainly is if it is well known... + + // FIXME This will never give us anything. When we get here, *it will + // never point at a string, but only at a character. I.e., if we are + // working on "sin(x)", then we are seeing: + // [char s mathalpha][char i mathalpha][char n mathalpha][delim ( ) [char x mathalpha]] + // and of course we will not find the function name "sin" in there, but + // rather "n(x)". + // + // It appears that we original ran extractStrings() before we ran + // extractFunctions(), but Andre changed this at f200be55, I think + // because this messed up what he was trying to do with "dx" in the + // context of integrals. + // + // This could be fixed by looking at a charSequence instead of just at + // the various characters, one by one. But I am not sure I understand + // exactly what we are trying to do here. And it involves a lot of + // guessing. if (!extractFunctionName(*it, name)) { // is this a user defined function? - // it it probably not, if it doesn't have a name. + // probably not, if it doesn't have a name. if (!extractString(*it, name)) continue; // it is not if it has no argument @@ -554,19 +590,20 @@ void extractFunctions(MathArray & ar) InsetMathDelim const * del = (*jt)->asDelimInset(); if (!del || del->cell(0).size() != 1) continue; - // fall trough into main branch + // fall through into main branch } // do we have an exponent like in // 'sin' '^2' 'x' -> 'sin(x)' '^2' - MathArray exp; + MathData exp; extractScript(exp, jt, ar.end(), true); // create a proper inset as replacement - auto_ptr p(new InsetMathExFunc(name)); + auto p = make_unique(buf, name); // jt points to the "argument". Get hold of this. - MathArray::iterator st = extractArgument(p->cell(0), jt, ar.end(), true); + MathData::iterator st = + extractArgument(p->cell(0), jt, ar.end(), kind, true); // replace the function name by a real function inset *it = MathAtom(p.release()); @@ -608,7 +645,7 @@ bool testIntegral(MathAtom const & at) return testIntSymbol(at) || ( at->asScriptInset() - && at->asScriptInset()->nuc().size() + && !at->asScriptInset()->nuc().empty() && testIntSymbol(at->asScriptInset()->nuc().back()) ); } @@ -622,18 +659,20 @@ bool testIntDiff(MathAtom const & at) // replace '\int' ['_^'] x 'd''x'(...)' sequences by a real InsetMathExInt // assume 'extractDelims' ran before -void extractIntegrals(MathArray & ar) +void extractIntegrals(MathData & ar, ExternalMath kind) { // we need at least three items... if (ar.size() < 3) return; + Buffer * buf = ar.buffer(); + //lyxerr << "\nIntegrals from: " << ar << endl; for (size_t i = 0; i + 1 < ar.size(); ++i) { - MathArray::iterator it = ar.begin() + i; + MathData::iterator it = ar.begin() + i; // search 'd' - MathArray::iterator jt = + MathData::iterator jt = endNestSearch(it, ar.end(), testIntegral, testIntDiff); // something sensible found? @@ -645,17 +684,17 @@ void extractIntegrals(MathArray & ar) continue; // core ist part from behind the scripts to the 'd' - auto_ptr p(new InsetMathExInt(from_ascii("int"))); + auto p = make_unique(buf, from_ascii("int")); // handle scripts if available if (!testIntSymbol(*it)) { p->cell(2) = (*it)->asScriptInset()->down(); p->cell(3) = (*it)->asScriptInset()->up(); } - p->cell(0) = MathArray(it + 1, jt); + p->cell(0) = MathData(buf, it + 1, jt); // use the "thing" behind the 'd' as differential - MathArray::iterator tt = extractArgument(p->cell(1), jt + 1, ar.end()); + MathData::iterator tt = extractArgument(p->cell(1), jt + 1, ar.end(), kind); // remove used parts ar.erase(it + 1, tt); @@ -673,8 +712,8 @@ bool testTermDelimiter(MathAtom const & at) // try to extract a "term", i.e., something delimited by '+' or '-'. // returns position behind the term -MathArray::iterator extractTerm(MathArray & ar, - MathArray::iterator pos, MathArray::iterator last) +MathData::iterator extractTerm(MathData & ar, + MathData::iterator pos, MathData::iterator last) { while (pos != last && !testTermDelimiter(*pos)) { ar.push_back(*pos); @@ -706,42 +745,44 @@ bool testSum(MathAtom const & at) return testSumSymbol(at) || ( at->asScriptInset() - && at->asScriptInset()->nuc().size() + && !at->asScriptInset()->nuc().empty() && testSumSymbol(at->asScriptInset()->nuc().back()) ); } // replace '\sum' ['_^'] f(x) sequences by a real InsetMathExInt // assume 'extractDelims' ran before -void extractSums(MathArray & ar) +void extractSums(MathData & ar) { // we need at least two items... if (ar.size() < 2) return; + Buffer * buf = ar.buffer(); + //lyxerr << "\nSums from: " << ar << endl; for (size_t i = 0; i + 1 < ar.size(); ++i) { - MathArray::iterator it = ar.begin() + i; + MathData::iterator it = ar.begin() + i; // is this a sum name? if (!testSum(ar[i])) continue; // create a proper inset as replacement - auto_ptr p(new InsetMathExInt(from_ascii("sum"))); + auto p = make_unique(buf, from_ascii("sum")); // collect lower bound and summation index InsetMathScript const * sub = ar[i]->asScriptInset(); if (sub && sub->hasDown()) { // try to figure out the summation index from the subscript - MathArray const & ar = sub->down(); - MathArray::const_iterator xt = + MathData const & ar = sub->down(); + MathData::const_iterator xt = find_if(ar.begin(), ar.end(), &testEqualSign); if (xt != ar.end()) { // we found a '=', use everything in front of that as index, // and everything behind as lower index - p->cell(1) = MathArray(ar.begin(), xt); - p->cell(2) = MathArray(xt + 1, ar.end()); + p->cell(1) = MathData(buf, ar.begin(), xt); + p->cell(2) = MathData(buf, xt + 1, ar.end()); } else { // use everything as summation index, don't use scripts. p->cell(1) = ar; @@ -753,7 +794,7 @@ void extractSums(MathArray & ar) p->cell(3) = sub->up(); // use something behind the script as core - MathArray::iterator tt = extractTerm(p->cell(0), it + 1, ar.end()); + MathData::iterator tt = extractTerm(p->cell(0), it + 1, ar.end()); // cleanup ar.erase(it + 1, tt); @@ -783,9 +824,9 @@ bool testDiffItem(MathAtom const & at) } -bool testDiffArray(MathArray const & ar) +bool testDiffArray(MathData const & ar) { - return ar.size() && testDiffItem(ar.front()); + return !ar.empty() && testDiffItem(ar.front()); } @@ -798,11 +839,12 @@ bool testDiffFrac(MathAtom const & at) } -void extractDiff(MathArray & ar) +void extractDiff(MathData & ar) { + Buffer * buf = ar.buffer(); //lyxerr << "\nDiffs from: " << ar << endl; for (size_t i = 0; i < ar.size(); ++i) { - MathArray::iterator it = ar.begin() + i; + MathData::iterator it = ar.begin() + i; // is this a "differential fraction"? if (!testDiffFrac(*it)) @@ -815,39 +857,39 @@ void extractDiff(MathArray & ar) } // create a proper diff inset - auto_ptr diff(new InsetMathDiff); + auto diff = make_unique(buf); // collect function, let jt point behind last used item - MathArray::iterator jt = it + 1; + MathData::iterator jt = it + 1; //int n = 1; - MathArray numer(f->cell(0)); + MathData numer(f->cell(0)); splitScripts(numer); if (numer.size() > 1 && numer[1]->asScriptInset()) { // this is something like d^n f(x) / d... or d^n / d... // FIXME //n = 1; if (numer.size() > 2) - diff->cell(0) = MathArray(numer.begin() + 2, numer.end()); + diff->cell(0) = MathData(buf, numer.begin() + 2, numer.end()); else jt = extractTerm(diff->cell(0), jt, ar.end()); } else { // simply d f(x) / d... or d/d... if (numer.size() > 1) - diff->cell(0) = MathArray(numer.begin() + 1, numer.end()); + diff->cell(0) = MathData(buf, numer.begin() + 1, numer.end()); else jt = extractTerm(diff->cell(0), jt, ar.end()); } // collect denominator parts - MathArray denom(f->cell(1)); + MathData denom(f->cell(1)); splitScripts(denom); - for (MathArray::iterator dt = denom.begin(); dt != denom.end();) { + for (MathData::iterator dt = denom.begin(); dt != denom.end();) { // find the next 'd' - MathArray::iterator et + MathData::iterator et = find_if(dt + 1, denom.end(), &testDiffItem); // point before this - MathArray::iterator st = et - 1; + MathData::iterator st = et - 1; InsetMathScript const * script = (*st)->asScriptInset(); if (script && script->hasUp()) { // things like d.../dx^n @@ -855,11 +897,11 @@ void extractDiff(MathArray & ar) if (extractNumber(script->up(), mult)) { //lyxerr << "mult: " << mult << endl; for (int i = 0; i < mult; ++i) - diff->addDer(MathArray(dt + 1, st)); + diff->addDer(MathData(buf, dt + 1, st)); } } else { // just d.../dx - diff->addDer(MathArray(dt + 1, et)); + diff->addDer(MathData(buf, dt + 1, et)); } dt = et; } @@ -886,11 +928,12 @@ bool testRightArrow(MathAtom const & at) // replace '\lim_{x->x0} f(x)' sequences by a real InsetMathLim // assume 'extractDelims' ran before -void extractLims(MathArray & ar) +void extractLims(MathData & ar) { + Buffer * buf = ar.buffer(); //lyxerr << "\nLimits from: " << ar << endl; for (size_t i = 0; i < ar.size(); ++i) { - MathArray::iterator it = ar.begin() + i; + MathData::iterator it = ar.begin() + i; // must be a script inset with a subscript (without superscript) InsetMathScript const * sub = (*it)->asScriptInset(); @@ -902,24 +945,24 @@ void extractLims(MathArray & ar) continue; // subscript must contain a -> symbol - MathArray const & s = sub->down(); - MathArray::const_iterator st = find_if(s.begin(), s.end(), &testRightArrow); + MathData const & s = sub->down(); + MathData::const_iterator st = find_if(s.begin(), s.end(), &testRightArrow); if (st == s.end()) continue; // the -> splits the subscript int x and x0 - MathArray x = MathArray(s.begin(), st); - MathArray x0 = MathArray(st + 1, s.end()); + MathData x = MathData(buf, s.begin(), st); + MathData x0 = MathData(buf, st + 1, s.end()); // use something behind the script as core - MathArray f; - MathArray::iterator tt = extractTerm(f, it + 1, ar.end()); + MathData f; + MathData::iterator tt = extractTerm(f, it + 1, ar.end()); // cleanup ar.erase(it + 1, tt); // create a proper inset as replacement - *it = MathAtom(new InsetMathLim(f, x, x0)); + *it = MathAtom(new InsetMathLim(buf, f, x, x0)); } //lyxerr << "\nLimits to: " << ar << endl; } @@ -929,124 +972,60 @@ void extractLims(MathArray & ar) // combine searches // -void extractStructure(MathArray & ar) +void extractStructure(MathData & ar, ExternalMath kind) { //lyxerr << "\nStructure from: " << ar << endl; - splitScripts(ar); + if (kind != MATHML && kind != HTML) + splitScripts(ar); extractDelims(ar); - extractIntegrals(ar); - extractSums(ar); + extractIntegrals(ar, kind); + if (kind != MATHML && kind != HTML) + extractSums(ar); extractNumbers(ar); extractMatrices(ar); - extractFunctions(ar); - extractDets(ar); - extractDiff(ar); - extractExps(ar); - extractLims(ar); - extractStrings(ar); - //lyxerr << "\nStructure to: " << ar << endl; -} - - -void write(MathArray const & dat, WriteStream & wi) -{ - MathArray ar = dat; - extractStrings(ar); - wi.firstitem() = true; - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) { - (*it)->write(wi); - wi.firstitem() = false; - } -} - - -void normalize(MathArray const & ar, NormalStream & os) -{ - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - (*it)->normalize(os); -} - - -void octave(MathArray const & dat, OctaveStream & os) -{ - MathArray ar = dat; - extractStructure(ar); - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - (*it)->octave(os); -} - - -void maple(MathArray const & dat, MapleStream & os) -{ - MathArray ar = dat; - extractStructure(ar); - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - (*it)->maple(os); -} - - -void maxima(MathArray const & dat, MaximaStream & os) -{ - MathArray ar = dat; - extractStructure(ar); - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - (*it)->maxima(os); -} - - -void mathematica(MathArray const & dat, MathematicaStream & os) -{ - MathArray ar = dat; - extractStructure(ar); - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - (*it)->mathematica(os); -} - - -void mathmlize(MathArray const & dat, MathStream & os) -{ - MathArray ar = dat; - extractStructure(ar); - if (ar.size() == 0) - os << ""; - else if (ar.size() == 1) - os << ar.front(); - else { - os << MTag("mrow"); - for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it) - (*it)->mathmlize(os); - os << ETag("mrow"); + if (kind != MATHML && kind != HTML) { + extractFunctions(ar, kind); + extractDets(ar); + extractDiff(ar); + extractExps(ar); + extractLims(ar); + extractStrings(ar); } + //lyxerr << "\nStructure to: " << ar << endl; } - - namespace { - std::string captureOutput(std::string const & cmd, std::string const & data) + string captureOutput(string const & cmd, string const & data) { // In order to avoid parsing problems with command interpreters // we pass input data through a file - FileName const cas_tmpfile(tempName(FileName(), "casinput")); + // Since the CAS is supposed to read the temp file we need + // to unlock it on windows (bug 10262). + unique_ptr tempfile(new TempFile("casinput")); + tempfile->setAutoRemove(false); + FileName const cas_tmpfile = tempfile->name(); + tempfile.reset(); + if (cas_tmpfile.empty()) { lyxerr << "Warning: cannot create temporary file." << endl; - return std::string(); + return string(); } - std::ofstream os(cas_tmpfile.toFilesystemEncoding().c_str()); + ofstream os(cas_tmpfile.toFilesystemEncoding().c_str()); os << data << endl; os.close(); - std::string command = cmd + " < " + string command = cmd + " < " + quoteName(cas_tmpfile.toFilesystemEncoding()); lyxerr << "calling: " << cmd << "\ninput: '" << data << "'" << endl; cmd_ret const ret = runCommand(command); - unlink(cas_tmpfile); + cas_tmpfile.removeFile(); return ret.second; } - size_t get_matching_brace(std::string const & str, size_t i) + size_t get_matching_brace(string const & str, size_t i) { int count = 1; size_t n = str.size(); @@ -1064,7 +1043,7 @@ namespace { return npos; } - size_t get_matching_brace_back(std::string const & str, size_t i) + size_t get_matching_brace_back(string const & str, size_t i) { int count = 1; while (i > 0) { @@ -1081,7 +1060,7 @@ namespace { return npos; } - MathArray pipeThroughMaxima(docstring const &, MathArray const & ar) + MathData pipeThroughMaxima(docstring const &, MathData const & ar) { odocstringstream os; MaximaStream ms(os); @@ -1089,7 +1068,7 @@ namespace { docstring expr = os.str(); docstring const header = from_ascii("simpsum:true;"); - std::string out; + string out; for (int i = 0; i < 100; ++i) { // at most 100 attempts // try to fix missing '*' the hard way // @@ -1109,7 +1088,7 @@ namespace { // search line with "Incorrect syntax" istringstream is(out); - std::string line; + string line; while (is) { getline(is, line); if (line.find("Incorrect syntax") != npos) @@ -1129,11 +1108,11 @@ namespace { expr.insert(pos, from_ascii("*")); } - vector tmp = getVectorFromString(out, "$$"); + vector tmp = getVectorFromString(out, "$$"); if (tmp.size() < 2) - return MathArray(); + return MathData(); - out = subst(tmp[1], "\\>", std::string()); + out = subst(subst(tmp[1], "\\>", string()), "{\\it ", "\\mathit{"); lyxerr << "output: '" << out << "'" << endl; // Ugly code that tries to make the result prettier @@ -1143,15 +1122,14 @@ namespace { size_t k = get_matching_brace(out, j + 1); k = get_matching_brace(out, k + 1); k = get_matching_brace(out, k + 1); - std::string mid = out.substr(i + 13, j - i - 13); + string mid = out.substr(i + 13, j - i - 13); if (mid.find("\\over") != npos) mid = '{' + mid + '}'; - out = out.substr(0,i) + out = out.substr(0, i) + mid + out.substr(k + 1); //lyxerr << "output: " << out << endl; i = out.find("\\mathchoice", i); - break; } i = out.find("\\over"); @@ -1162,23 +1140,23 @@ namespace { size_t k = get_matching_brace(out, i + 5); if (k == npos || k + 1 == out.size()) break; - out = out.substr(0,j - 1) + out = out.substr(0, j - 1) + "\\frac" - + out.substr(j,i - j) - + out.substr(i + 5,k - i - 4) + + out.substr(j, i - j) + + out.substr(i + 5, k - i - 4) + out.substr(k + 2); //lyxerr << "output: " << out << endl; i = out.find("\\over", i + 4); } - MathArray res; + MathData res; mathed_parse_cell(res, from_utf8(out)); return res; } - MathArray pipeThroughMaple(docstring const & extra, MathArray const & ar) + MathData pipeThroughMaple(docstring const & extra, MathData const & ar) { - std::string header = "readlib(latex):\n"; + string header = "readlib(latex):\n"; // remove the \\it for variable names //"#`latex/csname_font` := `\\it `:" @@ -1206,11 +1184,11 @@ namespace { //"#`latex/latex/symbol` " // " := subs((\\'_\\' = \\'`\\_`\\',eval(`latex/latex/symbol`)): "; - std::string trailer = "quit;"; + string trailer = "quit;"; odocstringstream os; MapleStream ms(os); ms << ar; - std::string expr = to_utf8(os.str()); + string expr = to_utf8(os.str()); lyxerr << "ar: '" << ar << "'\n" << "ms: '" << expr << "'" << endl; @@ -1229,7 +1207,7 @@ namespace { istringstream is(out); string line; getline(is, line); - if (line.find("on line") != 0) + if (!prefixIs(line, "on line")) break; // error message not identified getline(is, line); size_t pos = line.find('^'); @@ -1248,20 +1226,21 @@ namespace { // change \_ into _ // - MathArray res; + MathData res; mathed_parse_cell(res, from_utf8(out)); return res; } - MathArray pipeThroughOctave(docstring const &, MathArray const & ar) + MathData pipeThroughOctave(docstring const &, MathData const & ar) { odocstringstream os; OctaveStream vs(os); vs << ar; string expr = to_utf8(os.str()); string out; - + // FIXME const cast + Buffer * buf = const_cast(ar.buffer()); lyxerr << "pipe: ar: '" << ar << "'\n" << "pipe: expr: '" << expr << "'" << endl; @@ -1307,17 +1286,18 @@ namespace { // ansi control sequence before, such as '\033[?1034hans = ' size_t i = out.find("ans = "); if (i == string::npos) - return MathArray(); + return MathData(); out = out.substr(i + 6); // parse output as matrix or single number - MathAtom at(new InsetMathArray(from_ascii("array"), from_utf8(out))); + MathAtom at(new InsetMathArray(buf, from_ascii("array"), from_utf8(out))); InsetMathArray const * mat = at->asArrayInset(); - MathArray res; + MathData res(buf); if (mat->ncols() == 1 && mat->nrows() == 1) res.append(mat->cell(0)); else { - res.push_back(MathAtom(new InsetMathDelim(from_ascii("("), from_ascii(")")))); + res.push_back(MathAtom( + new InsetMathDelim(buf, from_ascii("("), from_ascii(")")))); res.back().nucleus()->cell(0).push_back(at); } return res; @@ -1372,7 +1352,7 @@ namespace { } - MathArray pipeThroughMathematica(docstring const &, MathArray const & ar) + MathData pipeThroughMathematica(docstring const &, MathData const & ar) { odocstringstream os; MathematicaStream ms(os); @@ -1391,7 +1371,7 @@ namespace { size_t pos2 = out.find("In[2]:="); if (pos1 == string::npos || pos2 == string::npos) - return MathArray(); + return MathData(); // get everything from pos1+17 to pos2 out = out.substr(pos1 + 17, pos2 - pos1 - 17); @@ -1402,16 +1382,229 @@ namespace { prettifyMathematicaOutput(out, "Muserfunction", true, false); prettifyMathematicaOutput(out, "Mvariable", false, false); - MathArray res; + MathData res; mathed_parse_cell(res, from_utf8(out)); return res; } } +} // anon namespace + +void write(MathData const & dat, WriteStream & wi) +{ + wi.firstitem() = true; + docstring s; + for (MathData::const_iterator it = dat.begin(); it != dat.end(); ++it) { + InsetMathChar const * const c = (*it)->asCharInset(); + if (c) + s += c->getChar(); + else { + if (!s.empty()) { + writeString(s, wi); + s.clear(); + } + (*it)->write(wi); + wi.firstitem() = false; + } + } + if (!s.empty()) { + writeString(s, wi); + wi.firstitem() = false; + } +} + + +void writeString(docstring const & s, WriteStream & os) +{ + if (!os.latex() || os.lockedMode()) { + os << (os.asciiOnly() ? escape(s) : s); + return; + } + + docstring::const_iterator cit = s.begin(); + docstring::const_iterator end = s.end(); + + // We may already be inside an \ensuremath command. + bool in_forced_mode = os.pendingBrace(); + + // We will take care of matching braces. + os.pendingBrace(false); + + while (cit != end) { + bool mathmode = in_forced_mode ? os.textMode() : !os.textMode(); + char_type const c = *cit; + docstring command(1, c); + try { + bool termination = false; + if (isASCII(c) || + Encodings::latexMathChar(c, mathmode, os.encoding(), command, termination)) { + if (os.textMode()) { + if (in_forced_mode) { + // we were inside \lyxmathsym + os << '}'; + os.textMode(false); + in_forced_mode = false; + } + if (!isASCII(c) && os.textMode()) { + os << "\\ensuremath{"; + os.textMode(false); + in_forced_mode = true; + } + } else if (isASCII(c) && in_forced_mode) { + // we were inside \ensuremath + os << '}'; + os.textMode(true); + in_forced_mode = false; + } + } else if (!os.textMode()) { + if (in_forced_mode) { + // we were inside \ensuremath + os << '}'; + in_forced_mode = false; + } else { + os << "\\lyxmathsym{"; + in_forced_mode = true; + } + os.textMode(true); + } + os << command; + // We may need a space if the command contains a macro + // and the last char is ASCII. + if (termination) + os.pendingSpace(true); + } catch (EncodingException const & e) { + switch (os.output()) { + case WriteStream::wsDryrun: { + os << "<" << _("LyX Warning: ") + << _("uncodable character") << " '"; + os << docstring(1, e.failed_char); + os << "'>"; + break; + } + case WriteStream::wsPreview: { + // indicate the encoding error by a boxed '?' + os << "{\\fboxsep=1pt\\fbox{?}}"; + LYXERR0("Uncodable character" << " '" + << docstring(1, e.failed_char) + << "'"); + break; + } + case WriteStream::wsDefault: + default: + // throw again + throw(e); + } + } + ++cit; + } + + if (in_forced_mode && os.textMode()) { + // We have to care for closing \lyxmathsym + os << '}'; + os.textMode(false); + } else { + os.pendingBrace(in_forced_mode); + } +} + + +void normalize(MathData const & ar, NormalStream & os) +{ + for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->normalize(os); +} + + +void octave(MathData const & dat, OctaveStream & os) +{ + MathData ar = dat; + extractStructure(ar, OCTAVE); + for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->octave(os); +} + + +void maple(MathData const & dat, MapleStream & os) +{ + MathData ar = dat; + extractStructure(ar, MAPLE); + for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->maple(os); +} + + +void maxima(MathData const & dat, MaximaStream & os) +{ + MathData ar = dat; + extractStructure(ar, MAXIMA); + for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->maxima(os); +} + + +void mathematica(MathData const & dat, MathematicaStream & os) +{ + MathData ar = dat; + extractStructure(ar, MATHEMATICA); + for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->mathematica(os); +} + + +void mathmlize(MathData const & dat, MathStream & os) +{ + MathData ar = dat; + extractStructure(ar, MATHML); + if (ar.empty()) + os << ""; + else if (ar.size() == 1) + os << ar.front(); + else { + os << MTag("mrow"); + for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->mathmlize(os); + os << ETag("mrow"); + } +} + + +void htmlize(MathData const & dat, HtmlStream & os) +{ + MathData ar = dat; + extractStructure(ar, HTML); + if (ar.empty()) + return; + if (ar.size() == 1) { + os << ar.front(); + return; + } + for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it) + (*it)->htmlize(os); +} + + +// convert this inset somehow to a number +bool extractNumber(MathData const & ar, int & i) +{ + idocstringstream is(charSequence(ar.begin(), ar.end())); + is >> i; + // Do not convert is implicitly to bool, since that is forbidden in C++11. + return !is.fail(); +} + + +bool extractNumber(MathData const & ar, double & d) +{ + idocstringstream is(charSequence(ar.begin(), ar.end())); + is >> d; + // Do not convert is implicitly to bool, since that is forbidden in C++11. + return !is.fail(); +} + -MathArray pipeThroughExtern(string const & lang, docstring const & extra, - MathArray const & ar) +MathData pipeThroughExtern(string const & lang, docstring const & extra, + MathData const & ar) { if (lang == "octave") return pipeThroughOctave(extra, ar); @@ -1435,15 +1628,15 @@ MathArray pipeThroughExtern(string const & lang, docstring const & extra, string data = to_utf8(os.str()); // search external script - support::FileName const file = libFileSearch("mathed", "extern_" + lang); + FileName const file = libFileSearch("mathed", "extern_" + lang); if (file.empty()) { lyxerr << "converter to '" << lang << "' not found" << endl; - return MathArray(); + return MathData(); } // run external sript - string out = captureOutput(file.absFilename(), data); - MathArray res; + string out = captureOutput(file.absFileName(), data); + MathData res; mathed_parse_cell(res, from_utf8(out)); return res; }